项目需求:实现类似微信文本消息放大界面中,长按自由复制效果,并且添加一些项目需要的操作项。
EditText本身具有长按一系列操作,但是长按后出现的系统本身的可操作UI实在是不想用,用过安卓的应该是知道这些操作长什么样的吧。
微信中,文本长按后操作就有只有3项,简单实用。所以我们需要自定义了。有关EditText自定义长按操作菜单样式,网上一搜一大批,可是基本离不开ActionMode,这个东西对于很多android机型来说是摆脱不了长按后会在ActionBar的位置悬浮上操作项的,所以并没有什么大作用。自己的android开发经验仅仅几年,有些东西并不知道如何下手,只能通过搜索看看别人是如何实现的,然后学习,积累经验。
关于自由复制,大家在网上可以搜到SelectableTextHelper这个项目(这里还要感谢所有开源的作者),项目地址https://github.com/laobie/SelectableTextHelper,这个就好很多了,down下来后,在使用中发现几个问题:
1、文本选中后是有背景色的,但是如果文本中包含表情符号,表情符号无法设置背景
2、在 Android 4.4 之前, Android 并不支持 emoji 表情,当时的解决方案主要是通过 imageSpan 配合 spannableString,来替换掉文字中的 emoji unicode 编码符号。
从 Android 4.4 开始, 官方开始了 emoji 表情的支持,实现原理基本就是通过把 emoji 表情内置在系统的 ttf 字体库中,对文本进行过滤后显示出 emoji 表情。
由于不同 Android 版本内置的 ttf 字体库对 emoji 表情的版本支持程度不同,导致老版本的 Android 对最新的 emoji 表情支持不全,所以一些 在新的 unicode 版本规范中被加入的 emoji 表情在老的 Android 设备上会显示方框乱码。
所以如果在按下的位置是emoji表情的位置(表情可以正常显示),首次选中就乱码了。
这两个问题还是急需解决的。
通过读代码发现,在设置选中文字背景色是用了BackgroundSpan的,但是BackgroundSpan仅仅对普通文字起作用,对表情符号并没有作用,所以关键还是在设置文字选择背景上。
然后我们发现EditText在长按选择文字时,背景色是可以作用在emoji上的,所以想到的解决方法是把TextView替换成EditText。
替换之后有几个关键点
1、布局中换成EditText,并添加属性textIsSelectable=true,这样EditText就不能被编辑,失去了光标
2、选中的背景色设置,调用setHighlightColor(color)方法
3、代码中,设置选中文字范围,把之前的span方法改为调用EditText.setSelection(int start,int end),重置为选中之前的效果,调用EditText.setSelection(0)就可以了。
修改后的关键方法如下:
private void selectText(int startPos, int endPos) {
if (startPos != -1) {
mSelectionInfo.mStart = startPos;
}
if (endPos != -1) {
mSelectionInfo.mEnd = endPos;
}
if (mSelectionInfo.mStart > mSelectionInfo.mEnd) {
int temp = mSelectionInfo.mStart;
mSelectionInfo.mStart = mSelectionInfo.mEnd;
mSelectionInfo.mEnd = temp;
}
mTextView.setSelection(mSelectionInfo.mStart, mSelectionInfo.mEnd);
if (mSpannable != null){
mSelectionInfo.mSelectionContent = mSpannable.subSequence(mSelectionInfo.mStart, mSelectionInfo.mEnd).toString();
if (mSelectListener != null) {
mSelectListener.onTextSelected(mSelectionInfo.mSelectionContent);
}
}
}
private void resetSelectionInfo() {
mSelectionInfo.mSelectionContent = null;
if (mSpannable != null) {
mTextView.setSelection(0);
}
}
之后就可以对表情符号也有选中效果了。然后把长按出现的弹框根据自己的需求替换成其他样式就行了。