[求助]LinkMovementMethod 和 ScrollingMovementMethod 冲突

jinl6 2020-02-01 04:00:37
各位大牛好,在 TextView 上我想要实现点击选中该句以及滑动屏幕滚屏两个功能. 分别的实现没有问题,但是同时要把这两个功能放在一起,发现有冲突. 滚屏无法实现. 求教可行的解决办法.

点击是使用了: ClickableSpan 方法
滚屏则是在 activity_mai.xml 添加了:
android:maxLines="10"
android:scrollbars="vertical"
这两个属性。

相关代码如下:

public class MainActivity extends AppCompatActivity{
TextView textView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

textView = (TextView)findViewById(R.id.word);
textView.setText(string2);

SpannableStringBuilder s = new SpannableStringBuilder(textView.getText());
textView.setText(s, TextView.BufferType.SPANNABLE);
getEachParagraph(textView);
textView.setMovementMethod(LinkMovementMethod.getInstance());
//textView.setMovementMethod(ScrollingMovementMethod.getInstance());
}

//paragraph
public void getEachParagraph(TextView textView) {
Spannable spans = (Spannable) textView.getText();
Integer[] indices = getIndices(
textView.getText().toString().trim(), '\n');
int start = 0;
int end = 0;
// recycle
//System.out.println("length of indices: " + indices.length);
//System.out.println("length of spans: " + spans.length());

for (int i = 0; i <= indices.length; i++) {
System.out.println("indices index: " + i);
//System.out.println("start of beginning: " + start);
ClickableSpan clickSpan = getClickableSpan(i);
//setSpan
end = (i < indices.length ? indices[i] : spans.length());
spans.setSpan(clickSpan, start, end,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
//System.out.println("end of ending: " + end);
start = end + 1;
}
//改变选中文本的高亮颜色
//textView.setHighlightColor(Color.parseColor("#0c83bd"));
}

//array
public static Integer[] getIndices(String s, char c) {
int pos = s.indexOf(c, 0);
List<Integer> indices = new ArrayList<Integer>();
while (pos != -1) {
indices.add(pos);
pos = s.indexOf(c, pos + 1);
}
return (Integer[]) indices.toArray(new Integer[0]);
}

//click
private ClickableSpan getClickableSpan(final int i) {

return new ClickableSpan() {
@Override
public void onClick(View widget) {
System.out.println("i: " + i);
TextView tv = (TextView) widget;
String s = tv
.getText()
.subSequence(tv.getSelectionStart(),
tv.getSelectionEnd()).toString();
Log.e("onclick--:", s);
}

@Override
public void updateDrawState(TextPaint ds) {
ds.setColor(Color.BLACK);
ds.setUnderlineText(false);
}
};
}
}
...全文
544 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
jinl6 2020-02-04
  • 打赏
  • 举报
回复
非常感谢版主的帮助。 把 onTouchEvent 略作修改,已经试过,可以用。继续修改去。感谢感谢!!!

    @Override
    public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
        if (mTouchSlop == 0) {
            mTouchSlop = ViewConfiguration.get(widget.getContext()).getScaledTouchSlop();
        }

        //ClickableSpan[] links;
        int action = event.getAction();
        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);

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                clickCount++;
                mIsMoved = false;
                //设置拖拽状态
                super.onTouchEvent(widget, buffer, event);

                if (links.length != 0) {
                    Selection.setSelection(buffer,
                            buffer.getSpanStart(links[0]),
                            buffer.getSpanEnd(links[0]));
                    return true;
                } else {
                    Selection.removeSelection(buffer);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (Math.abs(event.getX() - mDownX) > mTouchSlop ||
                        Math.abs(event.getY() - mDownY) > mTouchSlop) {
                    mIsMoved = true;
                }
                clickCount = 0;
                break;
            case MotionEvent.ACTION_UP:
                //清除拖拽状态
                super.onTouchEvent(widget, buffer, event);
                //ClickableSpan[] links = buffer.getSpans(off, off, ClickableSpan.class);
                //如果滑动,则不触发点击事件
                if (!mIsMoved && links.length != 0 && clickCount == 2) {
                    links[0].onClick(widget);
                    clickCount = 0;
                    return true;
                } else {
                    Selection.removeSelection(buffer);
                }
                break;
            default:
        }
        return super.onTouchEvent(widget, buffer, event);

    }
bdmh 2020-02-02
  • 打赏
  • 举报
回复
略作改动即可
textView.setMovementMethod(MyMovement.getInstance());

package my.study;

import android.text.Layout;
import android.text.NoCopySpan;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.LinkMovementMethod;
import android.text.method.MovementMethod;
import android.text.method.ScrollingMovementMethod;
import android.text.style.ClickableSpan;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

public class MyMovement 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 MyMovement();

        return sInstance;
    }

    private static MyMovement sInstance;
    private static Object FROM_BELOW = new NoCopySpan.Concrete();
}

bdmh 2020-02-01
  • 打赏
  • 举报
回复
如果你后设置ScrollingMovementMethod,那么前面的LinkMovementMethod就被替换掉了,LinkMovementMethod中会判断你点击的是哪个Span,然后触发Click事件,而ScrollingMovementMethod没有,你只能自己写一个支持这两种Movement的类,参考 源码组装一下。 或者不要ScrollingMovementMethod,而通过scrollview进行滑动

80,475

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧