logo头像

我有一个梦想

富文本选中状态方案

[TOC]

目标

文本长按出现可复制,点赞,搜索等操作。

section-1

方案一

实现步骤

  1. 首先TextView可以通过属性设置,允许选中,但弹出为系统弹窗

    1
    android:textIsSelectable="true"

    section-2

  2. 系统弹窗的样式与我们想要的还是有一些区别的,所以看起来弹窗的样式是需要我们自己定义的。
    这里其实有两套方案:

    1. 干掉所有系统的处理,即1,2部分都进行自定义
       .只进行弹窗的自定义部分,保留系统的选中状态,即保留2,自定义1
       这里同前端对了下方案,前端的方案与我们的2方案是一致的,所以我们可以保持一致,进行2方案的修改
    
  3. 实现自定义弹窗的方案是找到系统弹窗的创建地方,直接替换成我们的弹窗,通过读取API,我们找到了这个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
text.customSelectionActionModeCallback = object : ActionMode.Callback{
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return true
}

override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
//移除系统的menu项
menu?.clear()
//替换为自定义的menu项
mode?.menuInflater?.inflate(R.menu.select_menu,menu)
return false
}

override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
//处理自定义menu项的交互,eg:点击
return false
}

override fun onDestroyActionMode(mode: ActionMode?) {
}
}

接下来我们看效果:
section-3
OK,看起来没问题,但是这里有一个局限性,这里的view不可能做到完全自定义,这里的View说到底是一个menu菜单,和系统+AppTheme的设置有关,所以自由度有限

实践后发现小米系统是不支持自定义menu的,并且不走customSelectionActionModeCallback回调

方案二

不使用系统的选中复制功能,完全自定义选中效果

其一:可以减少系统的选中复制的crash量级

其二:可以越过某些厂商的限制。eg:小米

section-4

分析

弹窗分为3个部分,弹窗,左右游标,背景选中状态

弹窗:可通过自定义popupWindow实现

左右游标:可通过自定义popupWindow实现

背景选中状态:通过BackgroundSpan实现

大概思路是通过一个管理器,通过textview长按触发,获取选中的索引,计算左右浮标和弹窗的位置,针对选中索引,动态设置BackgroundSpan,弹窗设置isOutsideTouchable = true,当点击其他区域时使选中状态三部分消失,当点击左右浮标进行拖拽时,只消失弹窗,其他两者不消失,松手后,重新弹起弹窗。