持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
写过富文本开发的童鞋,应该都会面临这样一个情况,在对
EditText
进行编辑时,@了一个用户,界面上就会显示"@xxx",然后又突然想把这个"@xxx"删除掉,正常的行为应该是用户只点击一次虚拟键盘的删除按键,整条"@xxx"都应该被删除掉,而不是用户需要点击4次删除按键才能将"@xxx"给删除,或者是当光标滑动到"@xxx"特殊文本内部时,能直接跳转到该文本终点,本篇文章就是讲述如何实现这种效果 。
ClickableSpan
标识”@xxx“
一般我们@某个用户并在界面上显示时,会将”@xxx“这段@文本颜色高亮,并支持点击跳转到该用户的个人主页。
下面我们借助ClickableSpan
实现下:
val clickableSpan = object: ClickableSpan() {
override fun onClick(widget: View) {
//跳转到用户个人主页
}
override fun updateDrawState(ds: TextPaint) {
ds.color = ds.linkColor
ds.isUnderlineText = true
}
}
复制代码
其中:
- 重写
onClick
()方法实现点击跳转到用户个人主页的逻辑 重写updateDrawState()
方法,调用ds.color = xxx
设置”@xxx“文本显示颜色,一般默认设置ds.isUnderlineText = false
,使得”@xxx“文本不显示下划线
选中@xxx
再删除
首先我们要明确,当用户点击虚拟键盘删除按键时,要从EditText
具体删除哪段文本是由Selection
选中范围决定的,即删除的起为Selection.getSelectionStart()
对应下标,终点到Selection.getSelectionEnd()
对应下标。
所以,我们只需要在用户点击删除按键之后,手动调用EditText
的setSelection()
方法指定选中范围即可,在这个场景中,我们只需要获取到”@xxx“在EditText
中的起点和终点的位置即可,接下来我们一步步实现这个效果。
-
监听用户点击虚拟键盘的删除按钮
et.setOnKeyListener { v, keyCode, event -> if (keyCode == KeyEvent.KEYCODE_DEL && event.action == KeyEvent.ACTION_DOWN) { //监听键盘的点击删除按钮事件 } return@setOnKeyListener false } 复制代码
直接给
EditText
设置OnKeyListener
监听,并且点击的标识为KeyEvent.KEYCODE_DEL
就代表用户点击了删除按钮,请注意这个地方我们还判断了event.action == KeyEvent.ACTION_DOWN
,也就是说当用户点击了删除按钮并不管有没有移开,就直接执行删除,有利于用户的交互。 -
获取”@xxx“在
EditText
中的起始下标前面有讲,”@xxx“这段文本会被
ClickableSpan
标识,获取”@xxx“在文本的起始位置也就等价于获取ClickableSpan
在文本中渲染的起始位置,系统已经给我们提供好了便利的API://1. if (et.selectionEnd != et.selectionStart) { return@setOnKeyListener false } //2. val spans = et.text.getSpans(0, et.text.length, ClickableSpan::class.java) spans.find { //3. et.text.getSpanEnd(it) == et.selectionEnd }?.let { //如果存在满足上诉条件的ClickableSpan,则获取ClickableSpan的起始位置并直接选中该ClickableSpan val start = et.text.getSpanStart(it) val end = et.text.getSpanEnd(it) et.setSelection(start, end) } 复制代码
- 首先我们要判断当前文本选中的起始点是否相同,不相同代表当前已经指定的选中范围,直接跳过下面才做即可
- 借助
getSpans
获取EditText
文本中所有的ClickableSpan
类型数组,请注意,这个方法返回的Span的顺序是无序的 - 然后筛选
ClickableSpan
数组中ClickableSpan
标识的终点等于当前光标位置et.selectionEnd
的元素 - 如果找到符合上述条件的
ClickableSpan
,直接借助getSpanStart
和getSpanEnd
方法获取到该Span的起始点,这样也就代表着获取了”@xxx“在EditText
中的起始点,然后调用setSelection
方法进行选中即可
跳过一段特殊文本
- 首先还是要借助于
EditText
的setSpan
方法给这段特殊文本直接标识; - 我们可以通过
TextView
的方法onSelectionChanged()
监听光标所在的位置; - 借助于这个效果,以及上面讲的相关知识,判断当前光标是否处在这个特殊文本起始范围内;
- 存在,我们就将光标的位置重新定位到该特殊文本的结束位置,这样就实现了一段特殊文本的跳过
这里就不再给大家实操了,按照上面所讲的思路,也是很容易实现的,就不再过多赘述了。
总结
经过上面的几步操作,我们就可以实现文章一开头说的效果:点击一次删除按钮,就能直接将光标之前的”@xxx“完整删除;或者跳过一段特殊文本。核心就是要给这段特殊文本通过setSpan方法增加一个标识才行。