Android开发:自由选择TextView的文字

移动开发 Android
本文将介绍一下在Android下自由选择TextView的文字。用过EditText的都知道,EditText有个特点,ContextMenu提供了选择文字、复制、剪切等功能。如果直接就在view上选择文字,那样会更加方便。本文将教你如何自由选择TextView的文字。

我们介绍过一系列Android开发的教程,比如《如何实现TCP和UDP传输》、《在MyEclipse 8.6上搭建Android开发环境》,今天我们来介绍一下在Android下自由选择TextView的文字。

51CTO推荐专题:Android开发应用详解

用过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;    
}   
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

现在测试一下,发现长按没反应了,所料不错,就是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;    
    }    
}    
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.

【编辑推荐】

  1. Android开发:如何实现TCP和UDP传输
  2. 多图详解 “Android UI”设计官方教程
  3. 图文并茂 在MyEclipse 8.6上搭建Android开发环境
  4. 两大动力指引Android向更多领域进军
  5. Android开发必备的21个免费资源和工具
责任编辑:佚名 来源: Javaeye博客
相关推荐

2009-12-30 09:54:35

Linux Ubunt

2010-05-06 10:17:19

Adobe CTO苹果

2015-05-21 14:33:00

OpenStackUnitedStack开源云

2013-03-28 15:47:53

TextView文字自

2012-12-28 14:23:12

Android开发TextView

2022-09-23 16:27:36

MozillaFirefox浏览器

2017-04-20 12:45:08

AndroidTextView

2013-04-07 10:09:00

Android开发TextView属性

2021-06-29 14:48:58

鸿蒙HarmonyOS应用

2013-07-04 14:54:24

Android

2011-03-23 10:00:54

2017-06-29 11:49:15

弹性

2012-11-20 18:04:30

VMware

2011-09-14 11:31:26

Android API

2020-08-17 09:26:25

风河VxWorksPython

2023-08-03 18:08:51

浏览器Linux

2010-03-17 16:48:21

无线网络选择

2012-12-25 13:54:28

AndroidTextview
点赞
收藏

51CTO技术栈公众号