详解 View 的构造函数

本文深入解析了自定义View的四个构造参数的意义及其应用场景,包括AttributeSet attrs的使用方法、int[] attrs的定义方式、defStyleAttr在主题样式中的作用以及defStyleRes的配置步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们经常用到自定义 View,它有四个参数,但往往不太关心它们,等用到的时候就很容易混淆,今天来看看它们到底是什么意思。

View( 
   Context context, 
   @Nullable AttributeSet attrs, 
   int defStyleAttr, 
   int defStyleRes 
) 

AttributeSet attrs

从 xml 中提取的 Attribute 集合,通过 context.obtainStyledAttributes 生成的 TypedArray 来访问。

context.obtainStyledAttributes( 
   AttributeSet set, 
   @StyleableRes int[] attrs, 
   @AttrRes int defStyleAttr, 
   @StyleRes int defStyleRes 
)

它的参数和 View 的构造函数参数很像,多了一个 int[] attrs。

int[] attrs

它是一个 attribute 数组 ,可以来自一个 R.styleable.[name] 或自定义的 attribute 数组。

R.styleable.[name]

通过 declare-styleable 来声明一个 R.styleable.[name] 和多个 R.styleable.[name]_[attribute] ,如:

<declare-styleable name="HotTextView"> 
    <attr name="hello" format="string" /> 
    <attr name="bye" format="string" /> 
</declare-styleable> 

声明了 R.styleable.HotTextView 和它所包含的两个 attribute:R.styleable.HotTextView_hello、R.styleable.HotTextView_bye

既然 R.styleable.HotTextView 是一个数组,那 R.styleable.HotTextView[0] 和 R.styleable.HotTextView_hello 一样吗?
不一样!

R.styleable.HotTextView: [2130903157, 2130903414] 
R.styleable.HotTextView_hello: 1 
R.styleable.HotTextView_bye: 0 

可以看到,R.styleable.HotTextView_hello、R.styleable.HotTextView_bye 只是其代表的 attribute 在 R.styleable.HotTextView 数组中的 index,这个 index 是按照字母顺序排列的。

R.styleable.[name] 的使用:

val totalAttrArray = R.styleable.HotTextView 
val ta = context.obtainStyledAttributes(attrSet, totalAttrArray) 
val actualAttrArrayCount = ta.indexCount 
for (indexInActual in 0 until actualAttrArrayCount) { 
    val indexInTotal = ta.getIndex(indexInActual) 
    when (indexInTotal) { 
        R.styleable.HotTextView_bye -> { 
            // 处理 app:bye 
        } 
        R.styleable.HotTextView_hello -> { 
            // 处理 app:hello 
        } 
    } 
} 
ta.recycle() 

处理逻辑:

  • 通过 xml 得到 AttributeSet attrSet
  • 声明自己关心的 attribute 数组:totalAttrArray
  • 取 AttributeSet attrs、int[] attrs 中的 attribute 交集,得到一个实际的 attribute 数组(数组数量为 actualAttrArrayCount = ta.indexCount)
  • 遍历 actualAttrArray,通过它的 index 得到该 attribute 在 totalAttrArray 中的位置(indexInTotal = ta.getIndex(indexInActual))
  • 访问 attribute 数组中 int index 处的 attribute(ta.getText()、ta.getInt()、ta.getBoolean()…)

自定义 attribute 数组

熟悉了 R.styleable.[name] 的使用,就可以自定义 attribute 数组了,我们可以将自己关心的多个 attribute 合并入同一个 attribute 数组:

val totalAttrArray = intArrayOf( 
        android.R.attr.text, 
        android.R.attr.hint, 
        R.styleable.HotTextView[R.styleable.HotTextView_bye], 
        R.styleable.HotTextView[R.styleable.HotTextView_hello] 
) 
val ta = context.obtainStyledAttributes(attrSet, totalAttrArray) 
val actualAttrArrayCount = ta.indexCount 
for (indexInActual in 0 until actualAttrArrayCount) { 
    val indexInTotal = ta.getIndex(indexInActual) 
    when (indexInTotal) { 
        0 -> { 
            // 处理 android:text 
        } 
        1 -> { 
            // 处理 android:hint 
        } 
        2 -> { 
            // 处理 app:bye 
        } 
        3 -> { 
            // 处理 app:hello 
        } 
    } 
} 
ta.recycle() 

defStyleAttr

默认 attribute,他是一个 <attr>,要在 theme 中使用 。

要让它生效,需要配置四个地方:

attrs.xml

<resources> 
    <attr name="DefaultTabStyle" format="reference" /> 
</resources> 

自定义View

class BadgeTabView @JvmOverloads constructor(
        context: Context, 
        attributeSet: AttributeSet? = null, 
        defStyle: Int = R.attr.DefaultTabStyle 
) : TabLayout(context, attributeSet, defStyle) { 
} 

style.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> 
    ...
    <item name="DefaultTabStyle">@style/DefaultTabStyle</item> 
</style> 

<style name="DefaultTabStyle"> 
    ... 
</style> 

AndroidManifest.xml

<application 
    ... 
    android:theme="@style/AppTheme"> 
</application> 

defStyleRes

默认 style,它是一个 <style>,只在 defStyleAttr 为 0 时才被使用。

要使用它,只需配置两个文件即可

style.xml

<style name="CustomViewStyle"> 
    ... 
</style> 

自定义 View

@RequiresApi(Build.VERSION_CODES.LOLLIPOP) 
class CustomView @JvmOverloads constructor( 
        context: Context, 
        attrs: AttributeSet? = null, 
        defStyleAttr: Int = 0, 
        defStyleRes: Int =  
) : View(context, attrs, defStyleAttr, defStyleRes) { 
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值