怎么获取textview上触摸点的字符或者附近的字符?
来源:互联网 发布:一个ip开两家淘宝店 编辑:程序博客网 时间:2024/06/10 01:53
用过EditText的都知道,EditText有个特点,当在里面长按的时候,会出现一个ContextMenu,提供了选择文字、复制、剪切等功能。如果不出现这个ContextMenu,直接就在view上选择文字,那样会更加方便。于是作者就研究了一下EditText和TextView的代码,然后将这个问题解决了。
网上很多资料都说,要选择一段文字,只需要用Selection.getSelectionStart()和Selection.getSelectionEnd()确定选择的文字的头和尾,然后加颜色就行。作者经过测试,发现这个结果导致误导了很多人,是行不通的。
我们来分析一下解决办法。
TextView是很多View的基类,如Button、EditText都是继承自他,所以EditText里面的代码很少。我们看一下EditText的源码,有一个Override的getDefaultEditable方法,看名字的意思是是否可编辑,这个方法直接返回true。还有一个getDefaultMovementMethod方法,它返回的是ArrowKeyMovementMethod.getInstance(),通过查看ArrowKeyMovementMethod的源码,基本确定这个方法就是弹出ContextMenu和轨迹球监听的“元凶”。
下面,我们自己做一个view来打造自己的EditText。
我取名TextPage,继承EditText,在里面覆盖getDefaultEditable和getDefaultMovementMethod。
Java代码
@Override
public boolean getDefaultEditable() {
return false;
}
@Override
protected MovementMethod getDefaultMovementMethod() {
return null;
}
现在测试一下,发现长按没反应了,所料不错,就是getDefaultMovementMethod方法控制了ContextMenu。
看一下ArrowKeyMovementMethod的代码,里面提供了KeyEvent、轨迹球事件onTrackballEvent和touch事件onTouchEvent的处理。这些事件在何处调用的呢?我们看看TextView的onTouchEvent、onTrackballEvent和onKeyEvent方法里面就明白了,在这些事件回调中调用了ArrowKeyMovementMethod里面的这些方法。
还有个问题,ContextMenu在哪里触发的?这个问题,用过ContextMenu的都知道,view里面要使用ContextMenu,需要覆盖一个onCreateContextMenu方法,然后在里面创建ContextMenu的各个选项。在TextView里面找onCreateContextMenu,果然有,里面定义了选择、复制、粘贴等选项。
既然找到了这个,那么我们就可以进一步分析选择是如何做到的。
onCreateContextMenu只是创建菜单,那么菜单点击之后,触发了什么呢?
onCreateContextMenu里面定义了一个MenuHandler对象,然后作为参数传递给setOnMenuItemClickListener,找到MenuHandler,发现里面的onMenuItemClick返回的是onTextContextMenuItem函数,找到onTextContextMenuItem,OMG,终于找到点击menu触发的函数了。但是里面貌似没有关键的东西,选择的部分不在这里。那么,就应该在上面所说的那些事件里面了。
重点分析ArrowKeyMovementMethod的onTouchEvent方法。发现一个重要的方法getLayout(),然后获取一个Layout对象,通过x和y坐标知道当前字符串的offset位置。
那么,问题就可以完美的解决了。你可以点击任何地方然后拖动,释放之后,中间的文字就会被选中。
网上很多资料都说,要选择一段文字,只需要用Selection.getSelectionStart()和Selection.getSelectionEnd()确定选择的文字的头和尾,然后加颜色就行。作者经过测试,发现这个结果导致误导了很多人,是行不通的。
我们来分析一下解决办法。
TextView是很多View的基类,如Button、EditText都是继承自他,所以EditText里面的代码很少。我们看一下EditText的源码,有一个Override的getDefaultEditable方法,看名字的意思是是否可编辑,这个方法直接返回true。还有一个getDefaultMovementMethod方法,它返回的是ArrowKeyMovementMethod.getInstance(),通过查看ArrowKeyMovementMethod的源码,基本确定这个方法就是弹出ContextMenu和轨迹球监听的“元凶”。
下面,我们自己做一个view来打造自己的EditText。
我取名TextPage,继承EditText,在里面覆盖getDefaultEditable和getDefaultMovementMethod。
Java代码
@Override
public boolean getDefaultEditable() {
return false;
}
@Override
protected MovementMethod getDefaultMovementMethod() {
return null;
}
现在测试一下,发现长按没反应了,所料不错,就是getDefaultMovementMethod方法控制了ContextMenu。
看一下ArrowKeyMovementMethod的代码,里面提供了KeyEvent、轨迹球事件onTrackballEvent和touch事件onTouchEvent的处理。这些事件在何处调用的呢?我们看看TextView的onTouchEvent、onTrackballEvent和onKeyEvent方法里面就明白了,在这些事件回调中调用了ArrowKeyMovementMethod里面的这些方法。
还有个问题,ContextMenu在哪里触发的?这个问题,用过ContextMenu的都知道,view里面要使用ContextMenu,需要覆盖一个onCreateContextMenu方法,然后在里面创建ContextMenu的各个选项。在TextView里面找onCreateContextMenu,果然有,里面定义了选择、复制、粘贴等选项。
既然找到了这个,那么我们就可以进一步分析选择是如何做到的。
onCreateContextMenu只是创建菜单,那么菜单点击之后,触发了什么呢?
onCreateContextMenu里面定义了一个MenuHandler对象,然后作为参数传递给setOnMenuItemClickListener,找到MenuHandler,发现里面的onMenuItemClick返回的是onTextContextMenuItem函数,找到onTextContextMenuItem,OMG,终于找到点击menu触发的函数了。但是里面貌似没有关键的东西,选择的部分不在这里。那么,就应该在上面所说的那些事件里面了。
重点分析ArrowKeyMovementMethod的onTouchEvent方法。发现一个重要的方法getLayout(),然后获取一个Layout对象,通过x和y坐标知道当前字符串的offset位置。
那么,问题就可以完美的解决了。你可以点击任何地方然后拖动,释放之后,中间的文字就会被选中。
Java代码
import android.content.Context; import android.graphics.Color; import android.text.Layout; import android.text.Selection; import android.view.ContextMenu; import android.view.Gravity; import android.view.MotionEvent; import android.widget.EditText; /** * @author chroya */ public class TextPage extends EditText { private int off; //字符串的偏移值 public TextPage(Context context) { super(context); initialize(); } private void initialize() { setGravity(Gravity.TOP); setBackgroundColor(Color.WHITE); } @Override protected void onCreateContextMenu(ContextMenu menu) { //不做任何处理,为了阻止长按的时候弹出上下文菜单 } @Override public boolean getDefaultEditable() { return false; } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); Layout layout = getLayout(); int line = 0; switch(action) { case MotionEvent.ACTION_DOWN: line = layout.getLineForVertical(getScrollY()+ (int)event.getY()); off = layout.getOffsetForHorizontal(line, (int)event.getX()); Selection.setSelection(getEditableText(), off); break; case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_UP: line = layout.getLineForVertical(getScrollY()+(int)event.getY()); int curOff = layout.getOffsetForHorizontal(line, (int)event.getX()); Selection.setSelection(getEditableText(), off, curOff); break; } return true; } }
0 0
- 怎么获取textview上触摸点的字符或者附近的字符?
- 获取文章的字数或者字符数
- 获取文件或者字符的MD5值
- 获取触摸的点
- richedit怎么获取输入的宽字符
- 如何获取TextView中每个字符的长度
- 限制TextView的字符长度
- 有占位字符的textView
- 设置textView的占位字符
- linux获取一个文件的行数或者字符数
- Android中如何获取字符或者字符串的宽度
- 获取字符串中 某个字符或者某个字符串的个数
- 如何获取用户附近的商户或者其他好友(LBS)
- 获取TextView控件字符长度
- 墓碑上的字符
- 墓碑上的字符
- 获取字符串的字符
- 关于获取button控制或者编辑框控件或者静态文本框控件字符的操作
- 《Java并发编程从入门到精通》显示锁Lock和ReentrantLock
- 大规模高并发网站架构scala方案
- secureCRT中的vi显示多颜色
- svn: Can't revert without reverting parent
- PHP parse_str()函数
- 怎么获取textview上触摸点的字符或者附近的字符?
- Reveal简单使用
- 使用docker安装部署Spark集群来训练CNN(含Python实例)
- Android 上线前的代码混淆之(一)反编译
- Android ListView CheckBox状态错乱
- 10款轻量级JavaScript代码高亮插件
- 给MFC对话框控件添加鼠标浮动提示
- dfs搜索练习题 http://codeforces.com/problemset/problem/589/J
- 正则表达式规则