Android(安卓)设置完autoLink属性后自定义跳转到指定界面
在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
更多相关文章
- android 常用 属性
- ImageView 常用属性的分析
- Android(安卓)Switch属性全记录
- android 常用 属性
- ANDROID 输入法出现挤压屏幕、ANDROID输入键盘覆盖了屏幕控件的
- Android(安卓)模拟器横屏竖屏切换设置
- android环境变量的设置及注意问题
- (4.2.15)【android开源工具】Android画柱状图
- Android(安卓)实现水波纹动效