在前一次只能选择省份简称的基础上,增加了输入车牌号码的交互
这次主要是自己动手写代码实现:
1、动态生成7位的车牌输入框EditText
2、省份是选择的,车牌号是手动输入的
3、点击清除实现了最后一位的删除,并自动将焦点移动到前面框中
自己实现一些功能之后,确实发现kotlin能剩下很多代码,可读性也稍微变差了 -_-||
package com.example.mylogindemomvp.ui.carnumber import android.content.Context import android.graphics.Color import android.text.Editable import android.text.InputFilter import android.text.InputFilter.LengthFilter import android.text.TextWatcher import android.util.AttributeSet import android.util.TypedValue import android.view.Gravity import android.view.KeyEvent import android.widget.* import androidx.core.content.ContextCompat import com.example.mylogindemomvp.R import com.example.mylogindemomvp.util.AppUtils /** * 自定义车牌号选择器 */ class LicensePlateView: LinearLayout { companion object { val mLicensePlateList = arrayListOf( "京", "津", "渝", "沪", "冀", "晋", "辽", "吉", "黑", "苏", "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "琼", "川", "贵", "云", "陕", "甘", "青", "蒙", "桂", "宁", "新", "藏", "使", "领", "学", "港", "澳", ) // 拍照内容字符(禁用了O和I) val mLicenseNumberList = arrayListOf( "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ) } private var mSpacing = 10f // 间隔 private var mMarginLeftRight = 10f // 左边距 private var mMarginBottom = 0f // 下边距 private var mMarginTop = 60f // 上边距 private var mLength = 10 // 长度 private var mRectHeight = 88f // 每个格子高度 private var mRectMarginTop = 16f // 距离上边高度 private var mBackGroundColor = Color.TRANSPARENT // 背景颜色 private var mBackGroundImageRes:Int ?= null // 背景图片资源 private var mRectBackGround = R.drawable.view_shape_stroke_8548d2_radius_2 // 格子背景 private var mRectSelectBackGround = R.drawable.view_shape_stroke_8548d2_radius_2// 格子选中背景 private var editTextBackground = R.drawable.background_corner_trans_blue private var mCompleteText = "完成"//完成文字内容 private var mIsShowComplete = true //是否显示完成按钮 private var mClearText = "清除"//完成文字内容 private var mIsShowClear = true //是否显示清除按钮 private var mCompleteTextColor = Color.BLACK//完成按钮文字颜色 private var mCompleteTextSize = 18f//完成文字大小 private var mCompleteMarginTop = 20f//完成距离上边 private var mCompleteMarginBottom = 20f//完成距离上边 private var mCompleteMarginRight = 20f//完成距离右边 private var mRectTextSize = 16f//格子的文字大小 private var mRectTextColor = ContextCompat.getColor(context, R.color.text_333333)//格子文字的默认颜色 private var mRectSelectTextColor = ContextCompat.getColor(context, R.color.text_8548D2) // 格子文字的选中颜色 private var mNumProhibit = true // 默认禁止选择 private var mNumProhibitColor = ContextCompat.getColor(context, R.color.text_999999) private var mTempTextViewList = ArrayList<TextView>() // 存储临时View private var mTextClickEffect = true // 是否触发点击效果 private var mOldTextView:TextView = TextView(context) // 鄂A66666 val max_length = 7 var editTextList = ArrayList<EditText>(max_length); // 常用车牌号一般是7位 constructor(context: Context): super(context) { initData(context) } constructor(context: Context, attrs: AttributeSet?): super(context, attrs) { context.obtainStyledAttributes(attrs, R.styleable.LicensePlateView) .apply { // 整理的背景颜色 mBackGroundColor = getColor(R.styleable.LicensePlateView_lp_background, Color.parseColor("#F5F5F5")) mBackGroundImageRes = getResourceId(R.styleable.LicensePlateView_lp_background_img, -1) // 每个格子的默认背景 mRectBackGround = getResourceId(R.styleable.LicensePlateView_lp_rect_background, mRectBackGround) // 每个格子的选中背景 mRectSelectBackGround = getResourceId(R.styleable.LicensePlateView_lp_rect_background, mRectSelectBackGround) // 格子的文字大小 mRectTextSize = getDimension(R.styleable.LicensePlateView_lp_rect_text_size, mRectTextSize) // 格子的文字颜色 mRectTextColor = getColor(R.styleable.LicensePlateView_lp_rect_text_color, mRectTextColor) //格子的选中文字颜色 mRectSelectTextColor = getColor(R.styleable.LicensePlateView_lp_rect_select_text_color, mRectSelectTextColor) //每个格子的边距 mSpacing = getDimension(R.styleable.LicensePlateView_lp_rect_spacing, mSpacing) //每个格子的高度 mRectHeight = getDimension(R.styleable.LicensePlateView_lp_rect_height, mRectHeight) // 格子距离上边的距离 mRectMarginTop = getDimension(R.styleable.LicensePlateView_lp_rect_margin_top, mRectMarginTop) // 视图距离左右的距离 mMarginLeftRight = getDimension(R.styleable.LicensePlateView_lp_margin_left_right, mMarginLeftRight) //视图距离上边的距离 mMarginTop = getDimension(R.styleable.LicensePlateView_lp_margin_top, mMarginTop) //视图距离下边的距离 mMarginBottom = getDimension(R.styleable.LicensePlateView_lp_margin_bottom, mMarginBottom) //视图距离左右的距离 mMarginLeftRight = getDimension(R.styleable.LicensePlateView_lp_margin_left_right, mMarginLeftRight) //是否显示完成按钮 mIsShowComplete = getBoolean(R.styleable.LicensePlateView_lp_is_show_complete, true) //完成按钮文字颜色 mCompleteTextColor = getColor(R.styleable.LicensePlateView_lp_complete_text_color, Color.parseColor("#087EFD")) //完成按钮文字大小 mCompleteTextSize = getDimension( R.styleable.LicensePlateView_lp_complete_text_size, mCompleteTextSize ) //完成按钮文字内容 getString(R.styleable.LicensePlateView_lp_complete_text)?.let { mCompleteText = it } //完成按钮距离上边 mCompleteMarginTop = getDimension( R.styleable.LicensePlateView_lp_complete_margin_top, mCompleteMarginTop ) //完成按钮距离下边 mCompleteMarginBottom = getDimension( R.styleable.LicensePlateView_lp_complete_margin_bottom, mCompleteMarginBottom ) //完成按钮距离上边 mCompleteMarginRight = getDimension( R.styleable.LicensePlateView_lp_complete_margin_right, mCompleteMarginRight ) //是否触发点击效果 mTextClickEffect = getBoolean( R.styleable.LicensePlateView_lp_text_click_effect, mTextClickEffect ) this.recycle() } initData(context) } /** * 初始化数据 */ private fun initData(context: Context) { // 设置背景颜色 setBackgroundColor(mBackGroundColor) if(mBackGroundImageRes != -1) { mBackGroundImageRes?.let { setBackgroundResource(it) } } orientation = VERTICAL // 设置距离底部 setPadding(0, mMarginTop.toInt(), 0, mMarginBottom.toInt()) // 显示文本框 鄂 A 6 D 5 3 2 var topLayout = LinearLayout(context) var index = 0 while(index < max_length) { var editText = XZEditView(context).apply { tag = index setBackgroundResource(editTextBackground) setTextColor(Color.BLACK) setTextSize(TypedValue.COMPLEX_UNIT_SP, mCompleteTextSize) gravity = Gravity.CENTER maxLines = 1 filters = arrayOf<InputFilter>(LengthFilter(1)) // 限定长度 // inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS // 限定输入类型 weightSum = 1.0f editTextList.add(this) if(index == 0) { isEnabled = false // } else if(index == 1) { // inputType = InputType.TYPE_TEXT_FLAG_CAP_WORDS or InputType.TYPE_CLASS_NUMBER } // 添加输入监听,实现输入之后自动跳转下一个 val localIndex = index addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { if(inputCheck(localIndex, s.toString())) { focusToNext(localIndex) } } //输入后的监听} override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { println("beforeTextChanged") }//输入后的监听} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { println("onTextChanged") }//输入文字产生变化的监听} }) } // 调用Java 工具方法 var dp2 = AppUtils().dp2px(context, 2f) var editTextParams = LayoutParams(LayoutParams.MATCH_PARENT, AppUtils().dp2px(context, 42f), 1.0f) editTextParams.leftMargin = dp2 editTextParams.rightMargin = dp2 topLayout.addView(editText, editTextParams) index ++ } addView(topLayout) val actionLayout = LinearLayout(context) actionLayout.apply { orientation = HORIZONTAL gravity = Gravity.RIGHT } // “完成” 按钮是否显示? if(mIsShowComplete) { // 添加完成的View视图 val textView = TextView(context) textView.apply { setOnClickListener() { mKeyboardCompleted?.invoke() } gravity = Gravity.END text = mCompleteText setTextColor(mCompleteTextColor) setTextSize(TypedValue.COMPLEX_UNIT_SP, mCompleteTextSize) } actionLayout.addView(textView) val submitParams = textView.layoutParams as LayoutParams submitParams.apply { width = LayoutParams.WRAP_CONTENT topMargin = mCompleteMarginTop.toInt() bottomMargin = (mCompleteMarginBottom - mRectMarginTop).toInt() leftMargin = mCompleteMarginRight.toInt() rightMargin = mCompleteMarginRight.toInt() textView.layoutParams = this } } // “清除” 按钮是否显示? if(mIsShowClear) { // 添加完成的View视图 val textView = TextView(context) textView.apply { setOnClickListener { backspace() } gravity = Gravity.END text = mClearText setTextColor(mCompleteTextColor) setTextSize(TypedValue.COMPLEX_UNIT_SP, mCompleteTextSize) } actionLayout.addView(textView) val clearParams = textView.layoutParams as LayoutParams clearParams.apply { width = LayoutParams.WRAP_CONTENT topMargin = mCompleteMarginTop.toInt() bottomMargin = (mCompleteMarginBottom - mRectMarginTop).toInt() rightMargin = mCompleteMarginRight.toInt() textView.layoutParams = this } } // 操作栏添加到UI中 addView(actionLayout, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)) // 每行对应的省份简称 var layout: LinearLayout? = null mLicensePlateList.forEachIndexed{ index, s -> if(index % mLength == 0) { // 重新创建,并添加View layout = createLinearLayout() layout?.weightSum = 1f addView(layout) val params = layout?.layoutParams as LayoutParams params.apply { topMargin = mRectMarginTop.toInt() height = mRectHeight.toInt() leftMargin = mMarginLeftRight.toInt() rightMargin = mMarginLeftRight.toInt() - mSpacing.toInt() layout?.layoutParams = this } } //创建文字视图 val textView = TextView(context).apply { text = s //设置文字的属性 textSize = mRectTextSize // setTextSize(TypedValue.COMPLEX_UNIT_SP, mRectTextSize) //最后五个是否禁止 if (mNumProhibit && index > (mLicensePlateList.size - 6)) { setTextColor(mNumProhibitColor) mTempTextViewList.add(this) } else { setTextColor(mRectTextColor) } setBackgroundResource(mRectBackGround) gravity = Gravity.CENTER setOnClickListener { if (mNumProhibit && index > (mLicensePlateList.size - 6)) { return@setOnClickListener } // 点击的省份填充到第1个文本框 editTextList?.get(0).setText(text) //每个格子的点击事件 changeTextViewState(this) } } addRectView(textView, layout, 0.1f) } //追加最后一个删除按钮View,动态计算宽度 addEndView(layout) } private fun backspace() { val focusEditText = editTextList.filter { it.hasFocus() } var focusIndexInt: Int = if(focusEditText?.size > 0) { val focusIndex = focusEditText?.get(0).tag focusIndex as Int } else { max_length - 1 } editTextList?.get(focusIndexInt).setText("") if(focusIndexInt > 1) { editTextList?.get(focusIndexInt - 1).requestFocus() } } /** * 要实现键盘上的退格功能 */ override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if(event?.keyCode == KeyEvent.KEYCODE_BACK) { val focusEditText = editTextList.filter { it.hasFocus() } if(focusEditText?.size > 0) { val focusIndex = focusEditText?.get(0).tag focusEditText?.get(0).setText("") if(focusIndex as Int > 1) { // 这里涉及到强制类型转换 as editTextList?.get(focusIndex - 1).requestFocus() } } } return super.onKeyDown(keyCode, event) } /** * 输入校验 */ private fun inputCheck(index: Int, text: String): Boolean { if(index == 0) { return mLicensePlateList.contains(text) // 输入省份 } else { return mLicenseNumberList.contains(text) // 输入字母和数字 } } private fun focusToNext(index: Int) { editTextList?.get(index).clearFocus() if(index < max_length - 1) { editTextList?.get(index + 1).requestFocus() } } /** * AUTHOR:AbnerMing * INTRODUCE:追加最后一个View */ private fun addEndView(layout: LinearLayout?) { val endViewLayout = LinearLayout(context) endViewLayout.gravity = Gravity.END //删除按钮 val endView = RelativeLayout(context) //添加删除按钮 val deleteImage = ImageView(context) deleteImage.setImageResource(R.mipmap.icon_left) endView.addView(deleteImage) val imageParams = deleteImage.layoutParams as RelativeLayout.LayoutParams imageParams.addRule(RelativeLayout.CENTER_IN_PARENT) deleteImage.layoutParams = imageParams endView.setOnClickListener { //删除 mKeyboardDelete?.invoke() invalidate() } endView.setBackgroundResource(mRectBackGround) endViewLayout.addView(endView) val params = endView.layoutParams as LayoutParams params.width = (getScreenWidth() / mLength) * 2 - mMarginLeftRight.toInt() params.height = LayoutParams.MATCH_PARENT endView.layoutParams = params layout?.addView(endViewLayout) val endParams = endViewLayout.layoutParams as LayoutParams endParams.apply { width = (mSpacing * 3).toInt() height = LayoutParams.MATCH_PARENT weight = 0.4f rightMargin = mSpacing.toInt() endViewLayout.layoutParams = this } } private fun addRectView(view: TextView, layout: LinearLayout?, w: Float) { layout?.addView(view) val textParams = view.layoutParams as LayoutParams textParams.apply { weight = w width = 0 height = LayoutParams.MATCH_PARENT //每行的最后一个 rightMargin = mSpacing.toInt() view.layoutParams = this } } private fun changeTextViewState(textView: TextView) { if (mTextClickEffect) { //点击设置成效果 textView.setSelectTextStyle() textView.postDelayed({ textView.setUnSelectTextStyle() }, 300) } else { //记录上一个 mOldTextView?.setUnSelectTextStyle() textView.setSelectTextStyle() mOldTextView = textView } println("点击选择:" + textView.text) //每次点击后进行赋值 mKeyboardContent?.invoke(textView.text.toString()) } private fun TextView.setSelectTextStyle() { setBackgroundResource(mRectSelectBackGround) setTextColor(mRectSelectTextColor) } private fun TextView.setUnSelectTextStyle() { setBackgroundResource(mRectBackGround) setTextColor(mRectTextColor) } private fun createLinearLayout(): LinearLayout? { val layout = LinearLayout(context) layout.orientation = HORIZONTAL return layout } private var mKeyboardContent: ((content: String) -> Unit?)? = null fun keyboardContent(block: (String) -> Unit) { mKeyboardContent = block } /** * 键盘“完成”按键 */ private var mKeyboardCompleted: (() -> Unit)? = null fun keyboardCompleted(block: () -> Unit) { mKeyboardCompleted = block } /** * 键盘“删除”按键 */ private var mKeyboardDelete: (() -> Unit?)? = null fun keyboardDelete(block: () -> Unit) { mKeyboardDelete = block } fun openProhibit(isOpen: Boolean) { //禁止解开 mNumProhibit = isOpen mTempTextViewList.forEach { if (isOpen) { it.setTextColor(mRectTextColor) } else { it.setTextColor(mNumProhibitColor) } } } /** * 获取屏幕的宽 */ private fun getScreenWidth(): Int { return resources.displayMetrics.widthPixels } }
标签:02,LicensePlateView,Kotlin,private,学习,styleable,context,text,var From: https://www.cnblogs.com/LiuSiyuan/p/17431135.html