View 自定义 - 构造和属性 Constructor & Attribute

一、重写构造

没有空参构造必须重写,一共有四种(四参构造在 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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值