如何使具有LinkMovementMethod的TextView显示省略号?

15

我有一个需要放置在最多两行中并且其中的文本可以链接的 TexView

如果我将 LinkMovementMethod 设置为文本视图,我会得到一个可滚动的 TextView,而省略号会被忽略。

Xml 代码:

 <TextView
            android:id="@+id/text_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="4dip"
            android:clickable="true"
            android:maxLines="2"
            android:ellipsize="end"

            android:scrollHorizontally="false"
            android:scrollbars="horizontal"
            android:isScrollContainer="false"/>

这是我的活动:

public class MyActivity extends Activity {

    private TextView tv;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        tv = (TextView) findViewById(R.id.text_view);

        SpannableStringBuilder captionSpan = new SpannableStringBuilder();
        captionSpan.append("a very long text here a very long text here a very long text here a very long text here a very long text here a very long text here a very long text here a very long text here");
        captionSpan.setSpan(new CustomClickableSpan(), 1, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

        tv.setText(captionSpan);
        tv.setMovementMethod(LinkMovementMethod.getInstance());
    }

}


public class CustomClickableSpan extends android.text.style.ClickableSpan {

    @Override
    public void updateDrawState(TextPaint tp) {
        tp.setColor(tp.linkColor);
        tp.setUnderlineText(false);
    }

    @Override
    public void onClick(View widget) {
    }

}

如果我不设置移动方法,一切都正常工作。

2个回答

21

我找到了解决方案!
不要使用setMovementMethod(),而是使用OnTouchListener

String text = textView.getText().toString();
SpannableString spanText = new SpannableString(text);

//here set your spans to spanText

textView.setOnTouchListener(new TouchTextView(spanText));
textView.setText(spanText);

我从 LinkMovementMethod 类中得到了这个 onTouchEvent()

static class TouchTextView implements View.OnTouchListener {
    Spannable spannable;

    public TouchTextView (Spannable spannable){
        this.spannable = spannable;
    }
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int action = event.getAction();
        if(!(v instanceof TextView)){
            return false;
        }
        TextView textView  = (TextView) v;
        if (action == MotionEvent.ACTION_UP ||
                action == MotionEvent.ACTION_DOWN) {
            int x = (int) event.getX();
            int y = (int) event.getY();

            x -= textView.getTotalPaddingLeft();
            y -= textView.getTotalPaddingTop();

            x += textView.getScrollX();
            y += textView.getScrollY();

            Layout layout = textView.getLayout();
            int line = layout.getLineForVertical(y);
            int off = layout.getOffsetForHorizontal(line, x);

            ClickableSpan[] link = spannable.getSpans(off, off, ClickableSpan.class);

            if (link.length != 0) {
                if (action == MotionEvent.ACTION_UP) {
                    link[0].onClick(textView);
                } else if (action == MotionEvent.ACTION_DOWN) {
                    Selection.setSelection(spannable,
                            spannable.getSpanStart(link[0]),
                            spannable.getSpanEnd(link[0]));
                }

                return true;
            } else {
                Selection.removeSelection(spannable);
            }
        }

        return false;
    }
}

当然,TextView 应该具有这些属性:

android:maxLines="2"
android:ellipsize="end"

2
我真的不知道该如何感谢你!救了我一命! - DimitrisCBR
我很高兴能够帮助你。 - Airfreshener
好的 - 这刚刚救了我的一天。令人惊讶的是,谷歌还没有修复这个明显的缺陷... - slott
我真的不明白这个魔法是如何运作的,但它确实有效!它修复了TextView中明显的错误,其中自动链接或设置MovementMethod与对齐无法同时使用。非常感谢! - qkx

0
我需要比@Airfreshener提供的优秀解决方案稍微灵活一些的东西。希望能对其他人有所帮助。
应该能够使用ClickableSpanTextView代替TextView并进行删除和替换。根据您的需求,您可能需要为ClickableSpanTextView添加额外的构造函数。
public class ClickableSpanTextView extends TextView {

  static class SpannableClickListener implements View.OnTouchListener {

    private static SpannableClickListener defaultInstance;

    public static SpannableClickListener defaultInstance() {
      if (defaultInstance == null) {
        defaultInstance = new SpannableClickListener();
      }
      return defaultInstance;
    }

    private SpannableClickListener() {}

    @Override
    public boolean onTouch(View view, MotionEvent event) {
      if (!(view instanceof TextView)) {
        return false;
      }
      TextView textView = (TextView) view;

      CharSequence text = textView.getText();
      if (!(text instanceof Spannable)) {
        return false;
      }
      Spannable spannable = (Spannable) text;

      int action = event.getAction();
      if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        x -= textView.getTotalPaddingLeft();
        y -= textView.getTotalPaddingTop();

        x += textView.getScrollX();
        y += textView.getScrollY();

        android.text.Layout layout = textView.getLayout();
        int line = layout.getLineForVertical(y);
        int off = layout.getOffsetForHorizontal(line, x);

        ClickableSpan[] link = spannable.getSpans(off, off, ClickableSpan.class);

        if (link.length != 0) {
          if (action == MotionEvent.ACTION_UP) {
            link[0].onClick(textView);
          } else if (action == MotionEvent.ACTION_DOWN) {
            Selection.setSelection(
                spannable, spannable.getSpanStart(link[0]), spannable.getSpanEnd(link[0]));
          }

          return true;
        } else {
          Selection.removeSelection(spannable);
        }
      }

      return false;
    }
  }

  static class CompositeOnTouchListener implements View.OnTouchListener {
    OnTouchListener[] listeners;

    public CompositeOnTouchListener(OnTouchListener... listeners) {
      this.listeners = listeners;
    }

    @Override
    public boolean onTouch(View view, MotionEvent event) {
      for (OnTouchListener listener : listeners) {
        // Apply each touch listener in order until one returns true
        if (listener.onTouch(view, event)) {
          return true;
        }
      }
      return false;
    }
  }

  public ClickableSpanTextView(Context context, AttributeSet attrs) {
    super(context, attrs);
    super.setOnTouchListener(SpannableClickListener.defaultInstance());
  }

  @Override
  public void setOnTouchListener(OnTouchListener listener) {
    super.setOnTouchListener(
        new CompositeOnTouchListener(SpannableClickListener.defaultInstance(), listener));
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接