自定义MyButton:如何获取XML中声明的layout_width布局属性值?
问题需求
- 自定义
MyButton继承自MaterialButton,实现两种尺寸样式:- 大按钮:宽度为
match_parent,对应特定padding和文字大小 - 小按钮:最小宽度100dp,对应另一组padding和文字大小
- 大按钮:宽度为
- 需要获取XML中声明的
layout_width属性值,以此自动切换样式;此前尝试直接获取宽高返回0、doOnLayout未触发、自定义属性无效。
解决方案
1. 直接从AttributeSet解析XML中声明的layout_width属性
布局参数(如layout_width)可以通过AttributeSet直接读取XML中的原始声明值,无需等待布局完成。通过TypedValue解析属性值,判断是否为match_parent:
open class MyButton @JvmOverloads constructor( context: Context, private val attributeSet: AttributeSet? = null, private val styleAttribute: Int = com.google.android.material.R.attr.materialButtonStyle ) : MaterialButton(context, attributeSet, styleAttribute) { init { attributeSet?.let { parseAttr(it) } } private fun parseAttr(attr: AttributeSet) { // 获取layout_width的属性索引(使用Android官方命名空间) val widthIndex = attr.getAttributeIndex("http://schemas.android.com/apk/res/android", "layout_width") if (widthIndex != -1) { val typedValue = TypedValue() attr.getValue(widthIndex, typedValue) // 判断是否为match_parent val isMatchParent = typedValue.data == ViewGroup.LayoutParams.MATCH_PARENT if (isMatchParent) { // 大按钮样式:全屏宽度,设置对应padding和文字大小 setPadding(dpToPx(16), dpToPx(12), dpToPx(16), dpToPx(12)) textSize = 16f // 强制宽度撑满父布局(避免样式覆盖) layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT } else { // 小按钮样式:最小宽度100dp,设置对应padding和文字大小 minWidth = dpToPx(100) setPadding(dpToPx(8), dpToPx(8), dpToPx(8), dpToPx(8)) textSize = 14f } } } // dp转px工具方法 private fun dpToPx(dp: Int): Int { return (dp * resources.displayMetrics.density).toInt() } }
2. 修正doOnLayout未触发的问题(备选方案)
如果需要在布局完成后获取实际渲染宽高,可以通过addOnLayoutChangeListener替代doOnLayout(确保在UI线程执行):
init { addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> val parent = parent as? ViewGroup ?: return@addOnLayoutChangeListener val actualWidth = measuredWidth val parentWidth = parent.measuredWidth val isMatchParent = actualWidth == parentWidth // 根据实际宽度设置样式,逻辑同parseAttr方法 } }
注意事项
- 解析系统属性时必须使用Android官方命名空间
http://schemas.android.com/apk/res/android - 如果XML中
layout_width设置为固定dp值(如150dp),会被归类到小按钮样式;若需区分固定值和wrap_content,可进一步解析typedValue的类型和数值 - 若使用主题默认样式,需确保构造函数正确传入
styleAttribute参数
内容的提问来源于stack exchange,提问作者Shadman Wakil
相关产品推荐
相关产品推荐

