自定义组合控件步骤
- 继承ViewGroup比如LinearLayout、RelativeLayout
- 定义相关属性,获取相关属性
- 加载组合View
- 处理事件、根据属性修改View
- 定义接口,对外暴漏接口
NumberInputView效果图
实现步骤
1. 继承LinearLayout
class NumberInputView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
...
}
2. 定义相关属性,获取相关属性
在res->values->创建attrs.xml->定义属性
<resources>
<declare-styleable name="NumberInputView">
<attr name="min" format="integer"/><!--最小值-->
<attr name="max" format="integer"/><!--最大值-->
<attr name="step" format="integer"/><!--递增递减步数-->
<attr name="disable" format="boolean"/><!--加减号是否可点击-->
<attr name="defaultValue" format="integer"/><!--最小值-->
<attr name="textSize" format="integer|reference"/><!--字体大小-->
<attr name="btnBackground" format="reference"/><!--左右btn的背景色-->
</declare-styleable>
</resources>
获取属性
private fun initAttrs(context: Context, attrs: AttributeSet?) {
val attrs =
context.obtainStyledAttributes(attrs, R.styleable.NumberInputView)
min = attrs.getInteger(R.styleable.NumberInputView_min, -30)
max = attrs.getInteger(R.styleable.NumberInputView_max, 30)
step = attrs.getInteger(R.styleable.NumberInputView_step, 30)
textSize = attrs.getInteger(R.styleable.NumberInputView_textSize, 30)
defaultValue = attrs.getInteger(R.styleable.NumberInputView_defaultValue, 0)
mCurrentNumber = defaultValue
disable = attrs.getBoolean(R.styleable.NumberInputView_disable, false)
btnBackground = attrs.getResourceId(R.styleable.NumberInputView_btnBackground, -1)
attrs.recycle()
}
3. 加载组合View
加载View有三种方式:
//1
LayoutInflater.from(context).inflate(R.layout.view_number_input,this)
//2
LayoutInflater.from(context).inflate(R.layout.view_number_input,this,true)
//3
val view = LayoutInflater.from(context).inflate(R.layout.view_number_input,null)
addView(view)
inflate方法有三个参数,分别是 1.resource 布局的资源id 2.root 填充的根视图 3.attachToRoot 是否将载入的视图绑定到根视图中
配合Viewbinding加载view
private fun initView(context: Context) {
mBinding = ViewNumberInputBinding.inflate(LayoutInflater.from(context))
addView(mBinding?.root)
mBinding?.apply {
mNumberEt.textSize = textSize.toFloat()
mLeftBtn.isEnabled = !disable
mRightBtn.isEnabled = !disable
}
updateNumber()
}
4. 处理事件、根据属性修改View
处理点击事件,配合属性设置点击规则
private fun setUpEvent() {
mBinding?.apply {
mLeftBtn.setOnClickListener {
mRightBtn.isEnabled = true
mCurrentNumber -= step
if (min != 0 && mCurrentNumber <= min) {
mCurrentNumber = min
mLeftBtn.isEnabled = false
}
updateNumber()
}
mRightBtn.setOnClickListener {
mLeftBtn.isEnabled = true
mCurrentNumber += step
if (max != 0 && mCurrentNumber >= max) {
mCurrentNumber = max
mRightBtn.isEnabled = false
}
updateNumber()
}
}
}
5. 定义接口,对外暴漏接口
/**
* number改变监听
*/
fun onNumberChange(listener: (Int) -> Unit) {
mListener = listener
}
6. 调用
<com.kotlin.customview.compose.number.NumberInputView
android:id="@+id/mNumberInputView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:min="-30"
app:max="30"
app:step="7"
/>
activity中监听数值变化
mBinding.mNumberInputView.onNumberChange {
"number value change -> $it".e()
}