深入理解Attributeset

发布时间:2023-05-22

一、Attributeset简介

Attributeset是Android中一个重要的概念,可以理解为一组XML属性的集合,它用于在XML布局文件中定义View的属性。 在View的构造函数中使用AttributeSet参数,可以轻松地将XML文件中定义的相关属性设置到View当中,在代码中直接调用View的构造函数即可。 Attributeset的使用方式十分灵活,它能够方便地在不同的View中重用已有的属性集合,也能添加新的属性。

二、Attributeset的属性分类

Attributeset中的属性可以被分为三类:系统属性、自定义属性和样式属性。

1. 系统属性

系统属性即Android系统内置的属性,所有View都可以使用系统属性。这些属性在View的构造函数中通过AttributeSet参数传递,以设置View实例的相关属性。 比如idlayout_widthlayout_heighttextColor等属性。

2. 自定义属性

自定义属性是用户自己定义的属性,通过在XML文件中使用xmlns属性定义所属的命名空间,来将属性添加到View中。 例如,在res/values/attrs.xml中定义一个自定义命名空间,通过添加一个属性描述,在XML布局中就可以使用这个新的属性,来设置View的某些属性值。

<resources>
    <!-- 定义命名空间 -->
    <declare-styleable name="MyCustomView">
        <!-- 添加一个属性 -->
        <attr name="customAttr" format="boolean" />
    </declare-styleable>
</resources>

3. 样式属性

样式属性是在XML布局文件中设置一系列View属性的一种方式。 它和自定义属性的不同在于,它的属性值可以从其它的样式中来继承,简化了XML布局文件的编写并使得所有View的属性更加协调和一致。例如:

<style name="MyStyle">
    <item name="android:textColor">#FF0000</item>
    <item name="android:textSize">18sp</item>
</style>

使用样式属性时,可以通过style属性来指定,在View的构造函数中的AttributeSet中就会包含对应的样式属性。

三、Attributeset的使用技巧

1. 在View构造函数设置默认样式

在View的构造函数中可以设置默认的样式和属性,这样在XML布局文件中仅需要设置需要修改的属性,就能够有效地减少XML代码量,让代码更加简洁易懂。

class MyCustomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    // 设置默认值
    private var attr1 = 0
    private var attr2 = 0
    init {
        attrs?.let {
            // 读取自定义属性
            val a = context.obtainStyledAttributes(it, R.styleable.MyCustomView, defStyleAttr, 0)
            // 设置默认值
            attr1 = a.getInt(R.styleable.MyCustomView_customAttr1, 0)
            attr2 = a.getInt(R.styleable.MyCustomView_customAttr2, 0)
            a.recycle()
        }
    }
}

2. 通过自定义属性对View进行扩展

通过自定义属性,可以为现有的View添加新的功能,这种方式比自定义View要灵活得多。 例如,在一个自定义按钮中增加一个新的功能,当按钮被点击的时候,执行特定的动画效果:

<Button
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="My Button"
    app:animationOnClick="@anim/fade_in_fade_out" />

这里通过自定义属性animationOnClick来为按钮添加了一个新的功能,当点击按钮时会执行fadeInFadeOut动画。

3. 单个属性与多个属性的获取方式

在读取Attributeset中的属性时,有两种方式:单个属性的获取方式和多个属性的获取方式。 当仅需要获取单个属性时,可以使用getAttributeValue方法,例如:getAttrValue(attrs, android.R.attr.background)获取背景属性的值。 当需要获取多个属性或者属性组时,可以使用obtainStyledAttributes方法来获取,例如:

val a = context.obtainStyledAttributes(attrs, R.styleable.MyCustomView, defStyleAttr, 0)
val customAttr1 = a.getString(R.styleable.MyCustomView_customAttr1)
val customAttr2 = a.getString(R.styleable.MyCustomView_customAttr2)
a.recycle()

四、Attributeset的应用场景

在Android中,应用Attributeset的场景十分广泛,以下是一些常见的应用场景:

1. 自定义View的属性设置

当我们需要自定义View的时候,往往需要设置许多属性,通过Attributeset即可在XML布局文件中设置这些属性,大大简化了工作量和代码复杂度。

2. View的样式设置

在布局文件中,可以定义样式属性来统一设置特定类型的View的属性,同时可以继承其他的样式属性。

3. AppWidget的属性设置

AppWidget也是Android中支持Attributeset的地方之一,Attributeset可以保存AppWidget的所有配置属性,使得AppWidget的开发更加灵活易用。

4. Dialog的界面设计

Dialog是常用的一个组件,它通常需要实现一些自定义界面,Attributeset可以为Dialog界面的组件设置加载样式和自定义属性,便于实现细节控制。

5. RecyclerView的子项界面设计

RecyclerView中子项的布局也是可以使用Attributeset的,通过定义自定义的属性与值来设置复杂的子项界面,同时使得布局更加协调,减少代码量。

五、代码示例

布局文件中引用自定义属性MyCustomView

<com.example.view.MyCustomView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:customAttr1="123"
    app:customAttr2="45"/>

MyCustomView.kt自定义View的代码实现

class MyCustomView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    // 设置默认值
    private var attr1 = 0
    private var attr2 = 0
    init {
        attrs?.let {
            // 读取自定义属性
            val a = context.obtainStyledAttributes(it, R.styleable.MyCustomView, defStyleAttr, 0)
            // 设置默认值
            attr1 = a.getInt(R.styleable.MyCustomView_customAttr1, 0)
            attr2 = a.getInt(R.styleable.MyCustomView_customAttr2, 0)
            a.recycle()
        }
    }
}

自定义属性的定义方式

<resources>
    <!-- 定义命名空间 -->
    <declare-styleable name="MyCustomView">
        <!-- 添加自定义属性 -->
        <attr name="customAttr1" format="integer" />
        <attr name="customAttr2" format="integer" />
    </declare-styleable>
</resources>