ListView:带LinkMovementMethod的TextView使列表项无法点击?

Pat*_*oos 36 android

我想做什么:包含这样的消息的列表:

<UserName>,这是用户编写的mnessage,它将很好地包装到下一行.完全是这样的.

是)我有的:

ListView R.layout.list_item:

<TextView
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/text_message"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="(Message Text)" />
Run Code Online (Sandbox Code Playgroud)

膨胀以上布局的适配器并执行:

SpannableStringBuilder f = new SpannableStringBuilder(check.getContent());
f.append(username);
f.setSpan(new InternalURLSpan(new OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(context, "Clicked User", Toast.LENGTH_SHORT).show();
    }
}), f.length() - username.length(), f.length(),
        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

f.append(" " + message);

messageTextView.setText(f);
messageTextView.setMovementMethod(LinkMovementMethod.getInstance());
meesageTextView.setFocusable(false);
Run Code Online (Sandbox Code Playgroud)

InternalURLSpan类

public class InternalURLSpan extends ClickableSpan {
    OnClickListener mListener;

    public InternalURLSpan(OnClickListener listener) {
        mListener = listener;
    }

    @Override
    public void onClick(View widget) {
        mListener.onClick(widget);
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        super.updateDrawState(ds);
        ds.setUnderlineText(false);
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的活动中onCreate(...):

listView.setOnItemClickListener(ProgramChecksActivity.this);
Run Code Online (Sandbox Code Playgroud)

并执行上述内容

@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
    Toast.makeText(context, "Clicked Item", Toast.LENGTH_SHORT).show();
}
Run Code Online (Sandbox Code Playgroud)

问题:

点击该项目,不显示祝酒词.只需点击用户名即可显示祝酒词.

我猜,这setMovementMethod(LinkMovementMethod.getInstance());使得TextView可以点击.所以物品本身永远不会被点击了.

如何再次点击项目?拥有我想要的相同功能.

bab*_*bay 58

在这种情况下有三个显示停止者.的根本原因是,当你打电话setMovementMethod或者setKeyListener,TextView"修复",它的设置:

setFocusable(true);
setClickable(true);
setLongClickable(true);
Run Code Online (Sandbox Code Playgroud)

第一个问题是当View可以点击时 - 它总是消耗ACTION_UP事件(它返回true onTouchEvent(MotionEvent event)).
要解决此问题,只有在用户实际单击URL时,才应在该方法中返回true.

但是LinkMovementMethod,如果用户实际点击了链接,则不会告诉我们.onTouch如果用户单击链接,它将返回"true" ,但在许多其他情况下也是如此.

所以,实际上我在这里做了一个技巧:

public class TextViewFixTouchConsume extends TextView {

    boolean dontConsumeNonUrlClicks = true;
    boolean linkHit;

    public TextViewFixTouchConsume(Context context) {
        super(context);
    }

    public TextViewFixTouchConsume(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public TextViewFixTouchConsume(
        Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        linkHit = false;
        boolean res = super.onTouchEvent(event);

        if (dontConsumeNonUrlClicks)
            return linkHit;
        return res;

    }

    public void setTextViewHTML(String html)
    {
        CharSequence sequence = Html.fromHtml(html);
        SpannableStringBuilder strBuilder = 
            new SpannableStringBuilder(sequence);
        setText(strBuilder);
    }

    public static class LocalLinkMovementMethod extends LinkMovementMethod{
        static LocalLinkMovementMethod sInstance;


        public static LocalLinkMovementMethod getInstance() {
            if (sInstance == null)
                sInstance = new LocalLinkMovementMethod();

            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) {
                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[] link = buffer.getSpans(
                    off, off, ClickableSpan.class);

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

                    if (widget instanceof TextViewFixTouchConsume){
                        ((TextViewFixTouchConsume) widget).linkHit = true;
                    }
                    return true;
                } else {
                    Selection.removeSelection(buffer);
                    Touch.onTouchEvent(widget, buffer, event);
                    return false;
                }
            }
            return Touch.onTouchEvent(widget, buffer, event);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你应该打电话到某个地方

textView.setMovementMethod(
    TextViewFixTouchConsume.LocalLinkMovementMethod.getInstance()
);
Run Code Online (Sandbox Code Playgroud)

为textView设置此MovementMethod.

TextViewFixTouchConsume如果用户实际点击链接,则此MovementMethod会引发一个标记.(仅在ACTION_UPACTION_DOWN事件中)并且TextViewFixTouchConsume.onTouchEvent仅当用户实际点击链接时才返回true.

但那还不是全部!!!! 第三个问题是ListView(AbsListView)只有当项目视图没有焦点时才调用它的performClick方法(调用onItemClick事件处理程序)ListView.所以,你需要覆盖

@Override
public boolean hasFocusable() {
    return false;
}
Run Code Online (Sandbox Code Playgroud)

在您添加到的视图中ListView.(在我的情况下,这是一个包含textView的布局)

或者您可以setOnClickLIstener用于该视图.技巧不是很好,但它确实有效.

  • 对于任何需要它的人来说,这里是相应的Mono代码:http://pastebin.com/8SvMRaN9 (2认同)

Den*_*s K 44

babay的回答非常好.但是如果你不想继承TextView并且不关心LinkMovementMethod功能而不是点击链接你可以使用这种方法(这基本上是将LinkMovementMethod的onTouch功能复制到TextView的OnTouchListener中):

        myTextView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                boolean ret = false;
                CharSequence text = ((TextView) v).getText();
                Spannable stext = Spannable.Factory.getInstance().newSpannable(text);
                TextView widget = (TextView) v;
                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[] link = stext.getSpans(off, off, ClickableSpan.class);

                    if (link.length != 0) {
                        if (action == MotionEvent.ACTION_UP) {
                            link[0].onClick(widget);
                        }
                        ret = true;
                    }
                }
                return ret;
            }
        });
Run Code Online (Sandbox Code Playgroud)

只需将此侦听器分配给列表适配器getView()方法中的TextView即可.

  • 如果你问我,这个答案需要更多的支持. (2认同)

use*_*162 5

这是快速修复,使ListView项目和TextView UrlSpans可点击:

   private class YourListadapter extends BaseAdapter {

       @Override
       public View getView(int position, View convertView, ViewGroup parent) {
           ((ViewGroup)convertView).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);

           return convertView
       }

    }
Run Code Online (Sandbox Code Playgroud)

  • 这也适用于我的情况,除了我能够直接在XML中设置它:`android:descendantFocusability ="blocksDescendants"` (3认同)