Android:LinkMovementMethod滚动释放误触打开链接,需添加确认弹窗求助
解决TextView滚动时误触链接打开浏览器的问题
我太懂你这个头疼的困扰了——用LinkMovementMethod实现TextView滚动+链接点击时,只要滚动结束手指不小心落在链接上,就会直接跳浏览器,链接多的时候简直要崩溃!想要加个确认弹窗,得自定义MovementMethod来替换默认的实现,下面给你一步步讲怎么搞:
核心思路
默认的LinkMovementMethod会在手指抬起(ACTION_UP)时直接触发链接点击,我们要做的就是拦截这个动作:先判断是不是真的有意点击链接(不是滚动后的误触),然后弹出确认对话框,用户确认后再打开链接。
自定义ConfirmLinkMovementMethod
写一个继承自LinkMovementMethod的子类,重写onTouchEvent方法来实现我们的逻辑:
public class ConfirmLinkMovementMethod extends LinkMovementMethod { private static ConfirmLinkMovementMethod sInstance; private String mPressedUrl; // 单例模式,避免重复创建实例 public static ConfirmLinkMovementMethod getInstance() { if (sInstance == null) { sInstance = new ConfirmLinkMovementMethod(); } return sInstance; } @Override public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { int action = event.getAction(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { // 计算手指在TextView内容区域的坐标 int x = (int) event.getX() - widget.getTotalPaddingLeft() + widget.getScrollX(); int y = (int) event.getY() - widget.getTotalPaddingTop() + widget.getScrollY(); Layout layout = widget.getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); // 获取当前位置的ClickableSpan ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class); if (links.length != 0) { if (action == MotionEvent.ACTION_DOWN) { // 记录按下时的链接URL,用来区分滚动后的误触 mPressedUrl = getUrlFromSpan(buffer, links[0]); } else if (action == MotionEvent.ACTION_UP) { // 再次校验当前位置的链接和按下时是否一致,排除滚动误触 String currentUrl = getUrlFromSpan(buffer, links[0]); if (mPressedUrl != null && mPressedUrl.equals(currentUrl)) { // 弹出确认对话框 new AlertDialog.Builder(widget.getContext()) .setTitle("确认打开链接") .setMessage("是否要打开该链接?") .setPositiveButton("是", (dialog, which) -> links[0].onClick(widget)) .setNegativeButton("否", null) .show(); } mPressedUrl = null; } return true; } else { mPressedUrl = null; } } // 其他触摸事件(比如滚动)交给父类处理 return super.onTouchEvent(widget, buffer, event); } // 从URLSpan中提取链接地址(如果是自定义ClickableSpan,这里要对应修改) private String getUrlFromSpan(Spannable buffer, ClickableSpan span) { if (span instanceof URLSpan) { return ((URLSpan) span).getURL(); } return null; } }
替换默认的MovementMethod
把原来设置LinkMovementMethod的代码替换成我们自定义的:
// 原来的代码:textView.setMovementMethod(LinkMovementMethod.getInstance()); textView.setMovementMethod(ConfirmLinkMovementMethod.getInstance());
额外注意事项
- 确保你的TextView已经开启了滚动支持:在XML里加上
android:scrollbars="vertical",或者代码里设置textView.setVerticalScrollBarEnabled(true)。 - 如果你的TextView用了自定义的ClickableSpan(不是系统的URLSpan),需要修改
getUrlFromSpan方法,或者直接在确认回调里执行你自己的点击逻辑。
内容的提问来源于stack exchange,提问作者Rodrigo João Bertotti
相关产品推荐
相关产品推荐

