Kotlin自定义View实现一个通用的控件

效果图如下:

核心代码如下:

open class CommonItemView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, mode: Int = MODE_TEXT) : RelativeLayout(context, attrs, defStyleAttr) {

    companion object {

        const val MODE_TEXT = 0

        const val MODE_EDIT = 1
    }

    private lateinit var mTvRequireFlag: TextView

    private lateinit var mTvOrderKey: TextView

    private lateinit var mStubOrderItem: ViewStub

    private lateinit var mIvOrderGo: ImageView

    private lateinit var mTvItemValue: TextView

    private lateinit var mEtItemEdit: EditText

    private lateinit var mIvItemClear: ImageView

    private var isRequire: Boolean = false

    private var isGo: Boolean = true

    private var mKey: String? = ""

    private var mValue: String? = ""

    private var mHolder: String? = ""

    private var mLeftMargin: Int = dip(110)

    private var mMode: Int = mode

    init {
        val view = LayoutInflater.from(context).inflate(R.layout.view_order_item, this, true)
        initAttrs(attrs)
        initView(view)
        initData()
    }

    private fun initAttrs(attrs: AttributeSet?) {
        attrs?.apply {
            val array = context.obtainStyledAttributes(attrs, R.styleable.CommonItemView)
            isRequire = array.getBoolean(R.styleable.CommonItemView_orderRequired, false)
            isGo = array.getBoolean(R.styleable.CommonItemView_orderGo, true)
            mKey = array.getString(R.styleable.CommonItemView_orderKey) ?: ""
            mValue = array.getString(R.styleable.CommonItemView_orderValue) ?: ""
            mHolder = array.getString(R.styleable.CommonItemView_orderHolder) ?: ""
            mLeftMargin = array.getDimensionPixelSize(R.styleable.CommonItemView_orderLeftMargin, dip(110))
            mMode = array.getInt(R.styleable.CommonItemView_orderMode, MODE_TEXT)
            array.recycle()
        }
    }

    private fun initView(view: View) {
        mTvRequireFlag = view.findViewById(R.id.tv_require_flag)
        mTvOrderKey = view.findViewById(R.id.tv_order_key)
        mStubOrderItem = view.findViewById(R.id.stub_order_item)
        mIvOrderGo = view.findViewById(R.id.iv_order_go)
    }

    private fun initData() {
        setPadding(dip(16), 0, dip(16), 0)
        setBackgroundResource(R.color.white)
        //设置是否必填标志
        if (isRequire) {
            mTvRequireFlag.visibility = View.VISIBLE
        } else {
            mTvRequireFlag.visibility = View.GONE
        }
        //设置是否显示进入图标
        if (isGo) {
            mIvOrderGo.visibility = View.VISIBLE
        } else {
            mIvOrderGo.visibility = View.GONE
        }
        //设置Key
        mTvOrderKey.text = mKey
        if (mMode == MODE_EDIT) {
            mStubOrderItem.layoutResource = R.layout.order_stub_et
            val view = mStubOrderItem.inflate()
            mEtItemEdit = view.findViewById(R.id.stub_et)
            mEtItemEdit.hint = mHolder
            mEtItemEdit.setText(mValue)
            mIvItemClear = view.findViewById(R.id.stub_clear_iv)
            mEtItemEdit.addTextChangedListener(object : TextWatcher {
                override fun afterTextChanged(s: Editable?) {
                }

                override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
                }

                override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
                    if (s.isNullOrEmpty()) {
                        mIvItemClear.visibility = View.GONE
                    } else {
                        mIvItemClear.visibility = View.VISIBLE
                    }
                }
            })
            mIvItemClear.setOnClickListener {
                mEtItemEdit.setText("")
            }
        } else {
            mStubOrderItem.layoutResource = R.layout.order_stub_tv
            mTvItemValue = mStubOrderItem.inflate() as TextView
            mTvItemValue.hint = mHolder
            mTvItemValue.setHintTextColor(ContextCompat.getColor(context, R.color.btn_color_not_active))
            mTvItemValue.text = mValue
        }
        //设置横向的Margin
        val params = mStubOrderItem.layoutParams as LayoutParams
        params.setMargins(mLeftMargin, 0, 0, 0)
    }

    /**
     * 设置左侧Margin
     */
    fun setLeftMargin(leftMargin: Int) {
        mLeftMargin = leftMargin
        val params = mStubOrderItem.layoutParams as LayoutParams
        params.setMargins(mLeftMargin, 0, 0, 0)
    }

    /**
     * 展示进入箭头
     */
    fun showGo() {
        isGo = true
        mIvOrderGo.visibility = View.VISIBLE
    }

    /**
     * 隐藏进入箭头
     */
    fun hideGo() {
        isGo = false
        mIvOrderGo.visibility = View.GONE
    }

    /**
     * 设置Text模式下的TextView颜色
     */
    fun setFixTextColor() {
        if (mMode == MODE_TEXT) {
            mTvItemValue.textColorResource = R.color.text_item_fixed
        }
    }

    /**
     * 设置正常模式包含多选下的颜色
     */
    fun setNormalTextColor() {
        if (mMode == MODE_TEXT) {
            mTvItemValue.textColorResource = R.color.text_color_primary
        }
    }

    /**
     * 设置Key
     */
    fun setItemKey(key: String?) {
        mKey = key
        mTvOrderKey.text = key
    }

    fun setMode(mode: Int) {
        mMode = mode
    }

    /**
     * 改变Value
     */
    fun setItemValue(value: String?) {
        mValue = value
        if (mMode == MODE_TEXT) {
            mTvItemValue.text = value
        } else if (mMode == MODE_EDIT) {
            mEtItemEdit.setText(value)
        }
    }

    /**
     * 获取当前Value
     */
    fun getItemValue(): String {
        return mValue ?: ""
    }

    /**
     * 获取当前Edit-Value
     */
    fun getItemEdit(): String {
        var result = ""
        if (mMode == MODE_EDIT) {
            result = mEtItemEdit.text.toString().trim()
        }
        return result
    }

    /**
     * 获取当前的Key
     */

    fun getItemKey(): String {
        return mKey ?: ""
    }

    /**
     * 设置当前Item是否必填
     */
    fun setRequire(isRequire: Boolean) {
        this.isRequire = isRequire
        mTvRequireFlag.visibility = if (isRequire) {
            View.VISIBLE
        } else {
            View.GONE
        }
    }

    /**
     * 设置Holder
     */
    fun setItemHolder(holder: String?) {
        mHolder = holder
        if (mMode == MODE_TEXT) {
            mTvItemValue.hint = holder
        } else if (mMode == MODE_EDIT) {
            mEtItemEdit.apply {
                inputType = InputType.TYPE_CLASS_TEXT
                hint = holder
                imeOptions = EditorInfo.IME_ACTION_DONE
            }

        }
    }


    fun setMaxLength(maxLength: Int) {
        mEtItemEdit.filters = arrayOf(InputFilter.LengthFilter(maxLength))
    }

}

styles.xml文件自定义属性


    <declare-styleable name="CommonItemView">
        <attr name="orderRequired" format="boolean" />
        <attr name="orderGo" format="boolean" />
        <attr name="orderKey" format="string|reference" />
        <attr name="orderValue" format="string|reference" />
        <attr name="orderHolder" format="string|reference" />
        <attr name="orderLeftMargin" format="dimension|reference" />
        <attr name="orderMode" format="enum">
            <enum name="Edit" value="1" />
            <enum name="Text" value="2" />
        </attr>
    </declare-styleable>

布局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="5dp"
    android:paddingBottom="5dp">


    <TextView
        android:id="@+id/tv_order_key"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:maxWidth="100dp"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        android:textSize="14sp"
        android:textColor="#646B7F"
        android:text="ITEM名称" />

    <TextView
        android:id="@+id/tv_require_flag"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginEnd="5dp"
        android:layout_toEndOf="@id/tv_order_key"
        android:text="*"
        android:textColor="#f25f2b"
        android:textSize="15sp" />


    <ViewStub
        android:id="@+id/stub_order_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toStartOf="@+id/iv_order_go"
        android:paddingTop="10dp"
        android:paddingBottom="10dp"
        />


    <ImageView
        android:id="@+id/iv_order_go"
        android:layout_width="16dp"
        android:layout_height="16dp"
        android:layout_alignParentEnd="true"
        android:layout_centerVertical="true"
        android:layout_marginStart="3dp"
        android:src="@drawable/ic_arrow_grey_right" />


</RelativeLayout>

测试的例子:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <com.example.orderitemviewdemo.CommonItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:orderGo="false"
        app:orderKey="我是标题"
        app:orderValue="内容"
        app:orderLeftMargin="110dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginStart="16dp"
        android:background="#f4f4f4" />

    <com.example.orderitemviewdemo.CommonItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:orderGo="true"
        app:orderKey="我是标题"
        app:orderValue="内容"
        app:orderLeftMargin="110dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginStart="16dp"
        android:background="#f4f4f4" />

    <com.example.orderitemviewdemo.CommonItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:orderGo="false"
        app:orderKey="我是标题"
        app:orderHolder="我是提示语"
        app:orderLeftMargin="110dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginStart="16dp"
        android:background="#f4f4f4" />

    <com.example.orderitemviewdemo.CommonItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:orderGo="false"
        app:orderKey="我是标题"
        app:orderHolder="请输入内容"
        app:orderMode="Edit"
        app:orderLeftMargin="110dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_marginStart="16dp"
        android:background="#f4f4f4" />

    <com.example.orderitemviewdemo.CommonItemView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:orderGo="false"
        app:orderKey="我是标题"
        app:orderMode="Edit"
        app:orderHolder="请输入必填内容"
        app:orderLeftMargin="110dp"
        app:orderRequired="true"/>

</LinearLayout>

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Kotlin定义View中,可以通过重写`onInterceptTouchEvent`方法来限制子滑动件的滑动。在这个方法中,你可以判断是否要拦截事件,并返回`true`或`false`来决定是否拦截事件。如果返回`true`,则表示拦截事件,子滑动件将无法滑动;如果返回`false`,则表示不拦截事件,子滑动件可以正常滑动。 下面是一个示例,展示如何在自定义View中限制子滑动件的滑动。这个示例中创建了一个`CustomView`类,它包含一个`RecyclerView`作为子视图。我们想要在用户水平滑动`CustomView`时,防止`RecyclerView`的水平滑动,只允许垂直滑动: ``` class CustomView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : View(context, attrs, defStyleAttr) { private var initialX = 0f private var initialY = 0f private val recyclerView: RecyclerView init { LayoutInflater.from(context).inflate(R.layout.custom_view, this, true) recyclerView = findViewById(R.id.recyclerView) } override fun onInterceptTouchEvent(event: MotionEvent): Boolean { when (event.action) { MotionEvent.ACTION_DOWN -> { initialX = event.x initialY = event.y return false } MotionEvent.ACTION_MOVE -> { val dx = abs(event.x - initialX) val dy = abs(event.y - initialY) return dy > dx } else -> return super.onInterceptTouchEvent(event) } } } ``` 在`onInterceptTouchEvent`方法中,我们首先记录了用户按下手指时的坐标。然后,在用户移动手指时,我们计算水平和垂直方向上的滑动距离,并比较它们。如果垂直方向上的滑动距离大于水平方向上的滑动距离,则返回`true`,表示拦截事件,防止`RecyclerView`的滑动。否则,返回`false`,表示不拦截事件,`RecyclerView`可以正常滑动。 需要注意的是,在这个示例中,我们使用了`LayoutInflater`来从XML布局文件中获取`RecyclerView`视图。如果你使用了不同的方式来创建子视图,请相应地修改初始化代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值