赞
踩
我们知道MenuPanel是一个菜单面板容器,它里面可以放各式各样的菜单和菜单组。今天我们就来详细讲解输入菜单这个东西。
package dora.widget.panel.menu import android.content.Context import android.text.Editable import android.text.TextUtils import android.text.TextWatcher import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.EditText import android.widget.LinearLayout import dora.widget.panel.R import dora.widget.panel.MenuPanelItem import dora.widget.panel.MenuPanelItemRoot import dora.widget.panel.MenuPanelItemRoot.Companion.DEFAULT_MARGIN_TOP import dora.widget.panel.MenuPanelItemRoot.Companion.DEFAULT_TITLE_SPAN class InputMenuPanelItem @JvmOverloads constructor( override var marginTop: Int = DEFAULT_MARGIN_TOP, override var title: String? = "", private var titleSpan: MenuPanelItemRoot.Span = MenuPanelItemRoot.Span(DEFAULT_TITLE_SPAN), override val menuName: String? = MenuPanelItem.generateMenuName("InputMenuPanelItem"), private val hint: String? = "", private val content: String? = "", private val watcher: ContentWatcher? = null ) : MenuPanelItem { constructor(title: String, titleSpan: MenuPanelItemRoot.Span, hint: String, content: String, watcher: ContentWatcher? = null) : this(DEFAULT_MARGIN_TOP, title, titleSpan, MenuPanelItem.generateMenuName("InputMenuPanelItem"), hint, content, watcher) constructor(title: String, titleSpan: MenuPanelItemRoot.Span, hint: String, content: String) : this(title, titleSpan, hint, content, null) constructor(hint: String, content: String, watcher: ContentWatcher? = null) : this(DEFAULT_MARGIN_TOP, "", MenuPanelItemRoot.Span(DEFAULT_TITLE_SPAN), MenuPanelItem.generateMenuName("InputMenuPanelItem"), hint, content, watcher) constructor(hint: String, content: String) : this(hint, content, null) override fun initData(menuView: View) { val lp = LinearLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT ) lp.topMargin = marginTop menuView.layoutParams = lp val editText = menuView.findViewById<EditText>(ID_EDIT_TEXT_INPUT) editText.hint = hint if (!TextUtils.isEmpty(content)) { editText.setText(content) editText.setSelection(content!!.length) } if (watcher != null) { editText.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged( s: CharSequence, start: Int, count: Int, after: Int ) { } override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { watcher.onContentChanged(this@InputMenuPanelItem, s.toString()) } override fun afterTextChanged(s: Editable) {} }) } } override fun hasTitle(): Boolean { return title != null && title != "" } override fun getTitleSpan(): MenuPanelItemRoot.Span { return titleSpan } override fun setTitleSpan(titleSpan: MenuPanelItemRoot.Span) { this.titleSpan = titleSpan } override val layoutId: Int get() = R.layout.layout_menu_panel_input override fun inflateView(context: Context): View { return LayoutInflater.from(context).inflate(layoutId, null) } interface ContentWatcher { fun onContentChanged(item: InputMenuPanelItem, content: String) } companion object { @JvmField val ID_EDIT_TEXT_INPUT: Int = R.id.et_menu_panel_input } }
marginTop:上边距
title和titleSpan:标题和标题边距
menuName:菜单名称,在同一个MenuPanel保证唯一性
hint:输入提示信息,同android:hint
content:输入内容,同android:text
watcher:输入观察者,用来监听输入的字符
在这幅图中,就用到了几次InputMenuPanelItem。position分别为1、3、4和5。
不需要。我们知道,menuName作为MenuPanelItem的核心属性,需要保证其不重复,这样方便于我们找到它,并做相应的处理,如设置菜单的点击事件。但是在InputMenuPanelItem中,它的情况比较特殊,通常我们是不需要处理输入框的点击事件的。
所以框架在改进的过程中,最大限度的提供包容性。
companion object {
/**
* 虽然用它生成了默认的menuName,但是不建议你使用,最好使用业务的命名覆盖它。
*/
fun generateMenuName(prefix: String? = null) : String {
val uuid = UUID.randomUUID().toString()
return if (!TextUtils.isEmpty(prefix)) {
prefix + "-" + uuid.replace("-".toRegex(), "")
} else {
uuid.replace("-".toRegex(), "")
}
}
}
注释虽然这么写,但是它不是针对InputMenuPanelItem的。我们建议你就直接使用框架生成的menuName,所以构造函数都没有让你指定menuName,当然你也可以指定它。在InputMenuPanelItem中,默认的menuName它是一个“InputMenuPanelItem-”再加上随机字符串。
getCacheChildView()
推荐使用它,通过position和view的id去拿到。id有一个常量,InputMenuPanelItem.ID_EDIT_TEXT_INPUT,可以直接使用,避免你导R包冲突,要写一长串的包名。
companion object {
@JvmField
val ID_EDIT_TEXT_INPUT: Int = R.id.et_menu_panel_input
}
getCacheViewFromItem()
也可以使用它,需要你传入一个MenuPanelItem的属性先拿到根布局,再通过findViewById()进行查找。
拿到了EditText我们要给它设置限制条件就方便了。
如设置最多输入10个字符。
etInput.filters = arrayOf(InputFilter.LengthFilter(10))
如设置只能输入数字。
etInput.keyListener = DigitsKeyListener.getInstance("0123456789")
只能输入2位的正整数。
etInput.filters = arrayOf(InputFilter.LengthFilter(2), object : InputFilter { override fun filter( source: CharSequence?, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int ): CharSequence? { try { val input = Integer.parseInt(dest.toString() + source.toString()) if (input <= 0) { return ""; // 输入的数字小于或等于0,返回空字符串 } } catch (e: NumberFormatException) { return ""; // 输入的不是数字,返回空字符串 } return null } }) etInput.keyListener = DigitsKeyListener.getInstance("0123456789")
在这个案例中,你不设置DigitsKeyListener也是可以保证只输入两位的正整数的,但是有个问题就是,输入法默认不给你显示数字输入键盘,需要手动切换。
如设置多行输入,自定义光标。
etInput.layoutParams = LinearLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
DensityUtils.dp2px(300f)
)
etInput.gravity = Gravity.TOP
etInput.isSingleLine = false
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
etInput.textCursorDrawable = resources.getDrawable(R.drawable.edit_text_bg)
}
背景也可以定制,当然我们一般不这样做,有悖于框架的UI风格,哈哈。
不管怎么说,输入菜单InputMenuPanelItem都是一个举足轻重的核心菜单项,对于它的优化,可不能马虎。MenuPanel遵循低代码设计理念,目的是为了让大家写代码就像拼积木一样,把能想到的尽可能多的考虑到,写代码就跟玩一样。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。