在TextView 中设置autoLink 属性可以自动识别Web URL,电话号码,电子邮件地址添加下划线改变字体颜色并实现点击事件,支持自动识别的类型:

android:autoLink=“web” 匹配Web URL。

android:autoLink=“phone” 匹配电话号码

android:autoLink=“email” 匹配电子邮件地址

android:autoLink=“map” 匹配地理位置

android:autoLink=“all” 匹配所有可用的模式

android:autoLink=“none” 不匹配任何类型

也可以类似这样的设置 android:autoLink=“web|phone” 表示匹配web URL 和手机号

上面的属性也可以通过java 代码的形式对TextView 设置

setAutoLinkMask(int mask) 进行设置

设置的参数分别是:

Linkify.WEB_URLS 匹配Web UR

Linkify.PHONE_NUMBERS 匹配电话号码

Linkify.EMAIL_ADDRESSES 匹配电子邮件地址

Linkify.MAP_ADDRESSES 地理位置匹配

Linkify.ALL 匹配所有可用的模式

设置完antoLink属性,点击TextView中的链接时会跳转的对应的界面,比如点击网页的链接会跳转到系统的默认的浏览器界面,点击手机号会进入拨打电话界面,但是这都是系统默认的,我们可不可以进行拦截处理,跳转到我们指定的界面呢,当然是可以的。下面是我的拦截处理的方法。

继承 MovementMethod ,这里我们先看一下MovementMethod的源码,它的源码比较少

public class LinkMovementMethod extends ScrollingMovementMethod {    private static final int CLICK = 1;    private static final int UP = 2;    private static final int DOWN = 3;    @Override    public boolean canSelectArbitrarily() {        return true;    }    @Override    protected boolean handleMovementKey(TextView widget, Spannable buffer, int keyCode,            int movementMetaState, KeyEvent event) {        switch (keyCode) {            case KeyEvent.KEYCODE_DPAD_CENTER:            case KeyEvent.KEYCODE_ENTER:                if (KeyEvent.metaStateHasNoModifiers(movementMetaState)) {                    if (event.getAction() == KeyEvent.ACTION_DOWN &&                            event.getRepeatCount() == 0 && action(CLICK, widget, buffer)) {                        return true;                    }                }                break;        }        return super.handleMovementKey(widget, buffer, keyCode, movementMetaState, event);    }    @Override    protected boolean up(TextView widget, Spannable buffer) {        if (action(UP, widget, buffer)) {            return true;        }        return super.up(widget, buffer);    }            @Override    protected boolean down(TextView widget, Spannable buffer) {        if (action(DOWN, widget, buffer)) {            return true;        }        return super.down(widget, buffer);    }    @Override    protected boolean left(TextView widget, Spannable buffer) {        if (action(UP, widget, buffer)) {            return true;        }        return super.left(widget, buffer);    }    @Override    protected boolean right(TextView widget, Spannable buffer) {        if (action(DOWN, widget, buffer)) {            return true;        }        return super.right(widget, buffer);    }    private boolean action(int what, TextView widget, Spannable buffer) {        Layout layout = widget.getLayout();        int padding = widget.getTotalPaddingTop() +                      widget.getTotalPaddingBottom();        int areaTop = widget.getScrollY();        int areaBot = areaTop + widget.getHeight() - padding;        int lineTop = layout.getLineForVertical(areaTop);        int lineBot = layout.getLineForVertical(areaBot);        int first = layout.getLineStart(lineTop);        int last = layout.getLineEnd(lineBot);        ClickableSpan[] candidates = buffer.getSpans(first, last, ClickableSpan.class);        int a = Selection.getSelectionStart(buffer);        int b = Selection.getSelectionEnd(buffer);        int selStart = Math.min(a, b);        int selEnd = Math.max(a, b);        if (selStart < 0) {            if (buffer.getSpanStart(FROM_BELOW) >= 0) {                selStart = selEnd = buffer.length();            }        }        if (selStart > last)            selStart = selEnd = Integer.MAX_VALUE;        if (selEnd < first)            selStart = selEnd = -1;        switch (what) {        case CLICK:            if (selStart == selEnd) {                return false;            }            ClickableSpan[] link = buffer.getSpans(selStart, selEnd, ClickableSpan.class);            if (link.length != 1)                return false;            link[0].onClick(widget);            break;        case UP:            int bestStart, bestEnd;            bestStart = -1;            bestEnd = -1;            for (int i = 0; i < candidates.length; i++) {                int end = buffer.getSpanEnd(candidates[i]);                if (end < selEnd || selStart == selEnd) {                    if (end > bestEnd) {                        bestStart = buffer.getSpanStart(candidates[i]);                        bestEnd = end;                    }                }            }            if (bestStart >= 0) {                Selection.setSelection(buffer, bestEnd, bestStart);                return true;            }            break;        case DOWN:            bestStart = Integer.MAX_VALUE;            bestEnd = Integer.MAX_VALUE;            for (int i = 0; i < candidates.length; i++) {                int start = buffer.getSpanStart(candidates[i]);                if (start > selStart || selStart == selEnd) {                    if (start < bestStart) {                        bestStart = start;                        bestEnd = buffer.getSpanEnd(candidates[i]);                    }                }            }            if (bestEnd < Integer.MAX_VALUE) {                Selection.setSelection(buffer, bestStart, bestEnd);                return true;            }            break;        }        return false;    }    @Override    public boolean onTouchEvent(TextView widget, Spannable buffer,                                MotionEvent event) {        int action = event.getAction();        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {            int x = (int) event.getX();            int y = (int) event.getY();            x -= widget.getTotalPaddingLeft();            y -= widget.getTotalPaddingTop();            x += widget.getScrollX();            y += widget.getScrollY();            Layout layout = widget.getLayout();            int line = layout.getLineForVertical(y);            int off = layout.getOffsetForHorizontal(line, x);            ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class);            if (links.length != 0) {                if (action == MotionEvent.ACTION_UP) {                    links[0].onClick(widget);                } else if (action == MotionEvent.ACTION_DOWN) {                    Selection.setSelection(buffer,                        buffer.getSpanStart(links[0]),                        buffer.getSpanEnd(links[0]));                }                return true;            } else {                Selection.removeSelection(buffer);            }        }        return super.onTouchEvent(widget, buffer, event);    }    @Override    public void initialize(TextView widget, Spannable text) {        Selection.removeSelection(text);        text.removeSpan(FROM_BELOW);    }    @Override    public void onTakeFocus(TextView view, Spannable text, int dir) {        Selection.removeSelection(text);        if ((dir & View.FOCUS_BACKWARD) != 0) {            text.setSpan(FROM_BELOW, 0, 0, Spannable.SPAN_POINT_POINT);        } else {            text.removeSpan(FROM_BELOW);        }    }    public static MovementMethod getInstance() {        if (sInstance == null)            sInstance = new LinkMovementMethod();        return sInstance;    }    private static LinkMovementMethod sInstance;    private static Object FROM_BELOW = new NoCopySpan.Concrete();}

在上面的这段代码中处理界面跳转的只有这一行 links[0].onClick(widget);我们要实现自己的跳转只要在自定义的LinkMovementMethod的这一行进行处理就行了。
先定义一个替换links[0].onClick(widget);的接口

public interface LinkClickListener {    /**     * true  表示要自己处理  false 使用系统默认     *     * @param mURL     * @return     */    boolean onLinkClick(String mURL);}

定义一个LinkMovementMethod的子类 LinkMovementMethodEx,在onTouchEvent方法中做了判断,在我们应用自己处理的情况,就不在走系统的默认处理,只有我们自己不处理的情况下才走系统的。

public class LinkMovementMethodEx extends LinkMovementMethod {    private LinkClickListener listener;    public LinkMovementMethodEx(LinkClickListener listener) {        this.listener = listener;    }    @Override    public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {        int action = event.getAction();        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {            int x = (int) event.getX();            int y = (int) event.getY();            x -= widget.getTotalPaddingLeft();            y -= widget.getTotalPaddingTop();            x += widget.getScrollX();            y += widget.getScrollY();            Layout layout = widget.getLayout();            int line = layout.getLineForVertical(y);            int off = layout.getOffsetForHorizontal(line, x);            ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class);            if (links.length != 0) {                if (action == MotionEvent.ACTION_UP) {                    if (links[0] instanceof URLSpan) {                        URLSpan url = (URLSpan) links[0];                        if (listener != null && listener.onLinkClick(url.getURL())) {                            return true;                        } else {                            links[0].onClick(widget);                        }                    }                } else if (action == MotionEvent.ACTION_DOWN) {                    Selection.setSelection(buffer,                            buffer.getSpanStart(links[0]),                            buffer.getSpanEnd(links[0]));                }                return true;            } else {                Selection.removeSelection(buffer);            }        }        return super.onTouchEvent(widget, buffer, event);    }}

在项目中的引用

public class MainActivity extends Activity {    private String TAG = MainActivity.class.getSimpleName();    private TextView title;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        title = findViewById(R.id.tv_content);        title.setText(" 10086 中国移动的 这是百度的 https://www.baidu.com/");        title.setMovementMethod(new LinkMovementMethodEx(new LinkClickListener() {            @Override            public boolean onLinkClick(String mURL) {                //在这里执行直接的处理逻辑并将返回值设置为true                Log.i(TAG, "onLinkClick: " + mURL);                return false;            }        }));    }}

源码地址 https://github.com/songdaren123/TextLink

更多相关文章

  1. 【Android】MVC模式在Android系统中的应用
  2. 【源码】Android 面包屑导航效果源码、Android 各种侧边栏总结源
  3. Android - 约束布局实现一个简单的登陆界面
  4. Android注解:自定义注解之源码注解
  5. Android 计算器界面的实现
  6. android系统本身的图片资源
  7. Android(CM)源码国内镜像下载
  8. Android 统计图表引擎 AChartEngine(三) - 示例源码折线图、饼图
  9. Android 系统级应用守护进程

随机推荐

  1. android相对布局中@id和@+id的区别(原理)
  2. 游戏移植的注意事项
  3. Android最佳性能实践(四)——布局优化技
  4. 从Eclipse到Android(安卓)Studio经历
  5. android 显示gif图片实例详解
  6. android 和云计算
  7. 如何脱离Android源码环境编译aapt
  8. android listview 一行高亮
  9. java.lang.NullPointerException空指针问
  10. Android(安卓)XML解析学习——Pull方式