当前位置: 首页 > news >正文

Android低代码开发 - InputMenuPanelItem详解

我们知道MenuPanel是一个菜单面板容器,它里面可以放各式各样的菜单和菜单组。今天我们就来详细讲解输入菜单这个东西。

InputMenuPanelItem源码

package dora.widget.panel.menuimport 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_SPANclass 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 = marginTopmenuView.layoutParams = lpval editText = menuView.findViewById<EditText>(ID_EDIT_TEXT_INPUT)editText.hint = hintif (!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: Intget() = R.layout.layout_menu_panel_inputoverride fun inflateView(context: Context): View {return LayoutInflater.from(context).inflate(layoutId, null)}interface ContentWatcher {fun onContentChanged(item: InputMenuPanelItem, content: String)}companion object {@JvmFieldval ID_EDIT_TEXT_INPUT: Int = R.id.et_menu_panel_input}
}

属性解析

marginTop:上边距

title和titleSpan:标题和标题边距

menuName:菜单名称,在同一个MenuPanel保证唯一性

hint:输入提示信息,同android:hint

content:输入内容,同android:text

watcher:输入观察者,用来监听输入的字符

使用场景

  • 场景1,6个属性都传入,完全自定义
  • 场景2,只指定hint和content,其他用默认
  • 场景3,在场景2的基础上增加一个输入字符监听器
  • 场景4,指定标题、标题边距、hint和content
  • 场景5,在场景4的基础上再增加一个输入字符监听器

IMAGE 2024-06-13 16:24:44.jpg

在这幅图中,就用到了几次InputMenuPanelItem。position分别为1、3、4和5。

InputMenuPanelItem相较于直接使用EditText的优势

  1. 可以给输入框指定一个标题提示信息,而不同于hint,用户可以一直看到。同时它可以和hint一起使用,让hint显示校验规则等其他信息。
  2. 可以快捷的添加到MenuPanel,而不用考虑布局,写一大堆的属性,仅指定几个关键属性。

使用说明书

是否需要指定menuName

不需要。我们知道,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-”再加上随机字符串。

获取到InputMenuPanelItem里面的EditText

getCacheChildView()

推荐使用它,通过position和view的id去拿到。id有一个常量,InputMenuPanelItem.ID_EDIT_TEXT_INPUT,可以直接使用,避免你导R包冲突,要写一长串的包名。

companion object {@JvmFieldval ID_EDIT_TEXT_INPUT: Int = R.id.et_menu_panel_input
}
getCacheViewFromItem()

也可以使用它,需要你传入一个MenuPanelItem的属性先拿到根布局,再通过findViewById()进行查找。

设置最大长度限制和输入的字符限制

拿到了EditText我们要给它设置限制条件就方便了。

android:maxLength代码指定

如设置最多输入10个字符。

etInput.filters = arrayOf(InputFilter.LengthFilter(10))
android:digits代码指定

如设置只能输入数字。

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风格,哈哈。

MenuPanel的后期改进规划

  • 提供更多的MenuPanelItem
  • 可通过menuName获取到MenuPanelItem,当然这个API对于InputMenuPanelItem来说并没有什么用
  • 提供更贴心的构造函数,让使用者在用的时候可以少传参

总结

不管怎么说,输入菜单InputMenuPanelItem都是一个举足轻重的核心菜单项,对于它的优化,可不能马虎。MenuPanel遵循低代码设计理念,目的是为了让大家写代码就像拼积木一样,把能想到的尽可能多的考虑到,写代码就跟玩一样。

相关文章:

  • 2.spring cloud gateway 源码编译
  • (创新)基于VMD-CNN-BiLSTM的电力负荷预测—代码+数据
  • 表 达式树
  • 【NCBI】SRA toolkit安装及使用-WindowsLinux版本
  • 摄像头劫持——保护自己免受窥探
  • 【机器学习】机器学习重要方法—— 半监督学习:理论、算法与实践
  • 6.2 事件的创建,修改和删除
  • React native新架构组成
  • SQL server with方法修改
  • 两个src案例分享
  • SpringMVC框架学习笔记(八):自定义拦截器和异常处理
  • 第二十五篇——信息加密:韦小宝说谎的秘诀
  • R可视化:微生物相对丰度或富集热图可视化
  • RISC_CPU模块的调试
  • 开发一个python工具,pdf转图片,并且截成单个图片,然后修整没用的白边
  • 时间复杂度分析经典问题——最大子序列和
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • JS数组方法汇总
  • Linux Process Manage
  • oschina
  • PAT A1017 优先队列
  • Python学习之路16-使用API
  • Redis中的lru算法实现
  • SAP云平台运行环境Cloud Foundry和Neo的区别
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 基于Android乐音识别(2)
  • 近期前端发展计划
  • 判断客户端类型,Android,iOS,PC
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 在weex里面使用chart图表
  • 找一份好的前端工作,起点很重要
  • 《码出高效》学习笔记与书中错误记录
  • Python 之网络式编程
  • shell使用lftp连接ftp和sftp,并可以指定私钥
  • 阿里云ACE认证之理解CDN技术
  • ​Java基础复习笔记 第16章:网络编程
  • (1)(1.9) MSP (version 4.2)
  • (function(){})()的分步解析
  • (void) (_x == _y)的作用
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (九)One-Wire总线-DS18B20
  • (三)模仿学习-Action数据的模仿
  • (转)linux下的时间函数使用
  • *++p:p先自+,然后*p,最终为3 ++*p:先*p,即arr[0]=1,然后再++,最终为2 *p++:值为arr[0],即1,该语句执行完毕后,p指向arr[1]
  • ..回顾17,展望18
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .net core使用ef 6
  • .net mvc 获取url中controller和action
  • .NET 项目中发送电子邮件异步处理和错误机制的解决方案
  • @private @protected @public
  • [<死锁专题>]
  • [100天算法】-x 的平方根(day 61)
  • [2010-8-30]
  • [BSGS算法]纯水斐波那契数列