自定义组合控件-NumberInputView

408 阅读1分钟

自定义组合控件步骤

  1. 继承ViewGroup比如LinearLayout、RelativeLayout
  2. 定义相关属性,获取相关属性
  3. 加载组合View
  4. 处理事件、根据属性修改View
  5. 定义接口,对外暴漏接口

NumberInputView效果图

num.gif

实现步骤

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()
}

github地址