一、重写构造
没有空参构造必须重写,一共有四种(四参构造在 API21 加入)对应不同的创建方式。一般只需要重写前三个,通过 this 调用到三参构造中统一进行处理。
| 单参构造 |
View(Context context) 代码中 new 创建实例的时候调用。 |
| 双参构造 |
View(Context context, AttributeSet attrs) xml中使用时调用(xml转java代码的时候反射),attrs是xml中的属性。 |
| 三参构造 |
View(Context context, AttributeSet attrs, int defStyleAttr) 使用主题Style的时候调用。 |
class MyView : View {
//改成this调用2个参数的构造
constructor(context: Context?) : this(context, null)
//改成this调用3个参数的构造
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
//在3个参数的构造里统一进行处理
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
//TODO...
}
}
二、加载布局文件
|
public View inflate(int resource, ViewGroup root) 底层调用下面三参的重载,root != null 则 attachToRoot = true。 |
|
public View inflate(int resource, ViewGroup root, boolean attachToRoot) 参数resource:要加载的xml布局文件。 参数root:添加到哪个父容器中。若为null则resource布局文件最外层设置的属性都无效。 参数attachToRoot:是否将resource添加到root内。若为false,root显示的时候是没有resource的。 |
LayoutInflater.from(context).inflate(R.layout.drawer4,this)
//等价于
LayoutInflater.from(context).inflate(R.layout.drawer4,this, true)
//等价于
val view = LayoutInflater.from(context).inflate(R.layout.drawer4, this, false)
addView(view)
三、自定义属性
在 xml 中为控件设置的属性。自定义属性名称如果使用系统已定义的,例如 textSize 会在编译时报错,想使用需要定义为 <attr name=“android:text"/>
| 格式类型 | 定义/使用 |
|
string 字符串 |
<attr name = "myContent" format = "color" /> android:myContent = "Hello Word!" |
| color 颜色 |
<attr name = "myTextColor" format = "color" /> android:myTextColor = "#00FF00" |
| dimension 尺寸 |
单位:px、dp、sp。 <attr name = "myTextSize" format = "dimension" /> android:myTextSize = "12.sp" |
| reference 引用资源 |
<attr name = "myBackground" format = "reference" /> android:myBackground = "@drawable/图片ID" |
| boolean 布尔 |
<attr name = "myEnable" format = "boolean" /> android:myEnable = "true" |
|
float 浮点 |
<attr name = "myAlpha" format = "float" /> android:myAlpha = "0.5F" |
| integer 整型 |
<attr name = "myMaxLines" format = "integer" /> android:myMaxLines = "3" |
| fraction 百分比 |
<attr name = "myOffset" format = "fraction" /> android:myOffset = "10%" |
| enum 枚举 |
枚举类型的属性在使用时不能使用多个值 <attr name = "myOrientation"> <enum name = "horizontal" value="0" /> <enum name = "vertical" value="1" /> </attr> android:myOrientation = "vertical" 错误用法 android:myOrientation = “vertical|horizontal” |
| flag 位运算 |
位运算类型的属性在使用的过程中可以使用多个值 <attr name = "myGravity" /> <flag nema="top" value="0x01"> <flag nema="left" value="0x02"> <flag nema="center_vertical" value="0x02"> </attr> android:myGravity = "top|left" |
| 混合类型 |
属性定义时可以指定多种类型值 <attr name = "myBackground" format = "reference|color" /> android:myBackground = "@drawable/图片ID" android:myBackground = "#00FF00" |
3.1 创建资源文件(属性声明)
右键 values 目录 -> New File文件 -> 一般取名attrs.xml。
<resources>
<!--name使用自定义View的名称-->
<declare-styleable name="MyView">
<!--name属性名称,format格式-->
<attr name="myText" format="string" />
<attr name="myTextColor" format="color" />
<attr name="myTextSize" format="dimension" />
<attr name="myMaxLength" format="integer" />
<attr name="myBackground" format="reference|color" />
<!--枚举-->
<attr name="myInputType">
<enum name="number" value="1"/>
<enum name="text" value="2"/>
</attr>
</declare-styleable>
</resources>
3.2 构造函数中配置
重写一参、二参、三参构造,通过 this 调用到三参构造中统一处理。
class MyView : View {
private var text: String? = null
private var textSize: Int? = null
private var textColor: Int? = null
private var maxLength: Int? = null
private var background: Int? = null
private var inputType: Int? = null
//改成this调用2个参数的构造
constructor(context: Context?) : this(context, null)
//改成this调用3个参数的构造
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
//在这里统一进行处理
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
context?.let {
//返回一个与attrs中列举出的属性相关的数组,数组里面的值由样式属性指定
val attributes = it.obtainStyledAttributes(attrs, R.styleable.MyView)
//获取自定义属性(格式:属性名称_条目名称)
text = attributes.getString(R.styleable.MyView_myText)
textSize = attributes.getDimensionPixelSize(R.styleable.MyView_myTextSize, 0)
textColor = attributes.getColor(R.styleable.MyView_myTextColor, Color.BLACK)
maxLength = attributes.getInt(R.styleable.MyView_myMaxLength,1)
background = attributes.getResourceId(R.styleable.MyView_myBackground,R.drawable.ic_launcher_foreground)
inputType = attributes.getInt(R.styleable.MyView_myInputType,0)
//回收资源
attributes.recycle()
}
}
}
3.3 布局中使用(属性使用)
只有引入了命名空间,XML文件才知道下面使用的属性应该去哪里找(哪里定义的,不能凭空出现,要有根据。
- 根布局添加命名空间(只需要输入app,IDE会自动补全)。
- 控件名称使用完整路径(只需要输入自定义View的类名,IDE会自动补全)。
- 未自定义的属性View会去处理(继承自View),使用自定义的属性就是 app: 开头的。
<!--根布局添加命名空间-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!--控件名称使用完整路径-->
<com.example.kotlindemo.view.MyView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:myBackground="@drawable/ic_launcher_foreground"
app:myInputType="number"
app:myText="Hello Word!"
app:myTextColor="@color/black"
app:myTextSize="20sp"
app:myMaxLength="20"/>
</LinearLayout>
1517

被折叠的 条评论
为什么被折叠?



