ListView控件:TextView中与LinkMovementMethod使得列表项目无法点击? [英] ListView: TextView with LinkMovementMethod makes list item unclickable?

查看:149
本文介绍了ListView控件:TextView中与LinkMovementMethod使得列表项目无法点击?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要做的:像这样的邮件列表:

What I want to do: A list with messages like this:

<用户名>这里是用户写mnessage,这将很好地换到下一行。正是这样的。

<UserName> and here is the mnessage the user writes, that will wrap nicely to the next line. exactly like this.

我有什么:

的ListView R.layout.list_item:

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)" />

适配器的膨胀上面的布局和作用:

Adapter that inflates the above layout and does:

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);

在InternalURLSpan类

The InternalURLSpan class

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);
    }
}

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

listView.setOnItemClickListener(ProgramChecksActivity.this);

和上述

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

问题:

单击该项目,不显示敬酒。只有点击用户名不显示敬酒。

Clicking on the item, does not show the toast. Only clicking on the username does show the toast.

我猜测,那 setMovementMethod(LinkMovementMethod.getInstance()); 使TextView的点击。因此,项目本身并永远不会再点击。

I am guessing, that setMovementMethod(LinkMovementMethod.getInstance()); makes the TextView clickable. So the items themselves do never get clicked anymore.

我怎样才能使项目点击了吗?具有相同的功能,因为我想要的。

How can I make the items clickable again? Having the same functionality as I want.

推荐答案

有三行显示,瓶塞在这种情况下。根本原因是,当你调用 setMovementMethod setKeyListener 的TextView 修复它的设置:

There are THREE show-stoppers in this case. the root reason is that when you call setMovementMethod or setKeyListener, TextView "fixes" it's settings:

setFocusable(true);
setClickable(true);
setLongClickable(true);

所以,第一个原因是,当一个视图是点击 - 它总是消耗 ACTION_UP 事件(在的onTouchEvent(MotionEvent事件返回true) )。
为了解决这个问题,你应该返回true该方法仅在用户实际点击的URL。 但 LinkMovementMethod 并没有告诉我们,如果用户实际点击的链接。它返回真,在它的 onTouch 如果用户点击该链接,而且在其他许多情况下。

So, the first reason is that when a View is clickable - it always consumes ACTION_UP event (by returning true in onTouchEvent(MotionEvent event)).
To fix that you should return true in that method only if the user actually clicks the URL. But the LinkMovementMethod doesn't tell us, if the user actually clicked a link. It returns "true" in it's onTouch if the user clicks the link, but also in many other cases.

所以,其实我做了一个黑客在这里:

So, actually I did a hack here:

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);
        }
    }
}

您应该拨打什么地方

textView.setMovementMethod(
    TextViewFixTouchConsume.LocalLinkMovementMethod.getInstance()
);

要设置这个MovementMethod为TextView的。

to set this MovementMethod for the textView.

这MovementMethod提出的 TextViewFixTouchConsume 一个标志,如果用户实际点击链接。 (仅在 ACTION_UP ACTION_DOWN 事件)和 TextViewFixTouchConsume.onTouchEvent 返回true,只有当用户实际命中链接。

This MovementMethod raises a flag in TextViewFixTouchConsume if user actually hits link. (only in ACTION_UP and ACTION_DOWN events) and TextViewFixTouchConsume.onTouchEvent returns true only if user actually hit link.

不过,这还不是全部!!!! 第三个问题是,的ListView AbsListView )调用它的 performClick 方法(即调用 onItemClick 事件处理程序)仅的ListView 的项目视图没有focusables。 所以,你需要重写

But that's not all!!!! The third problem is that ListView (AbsListView) calls it's performClick method (that calls onItemClick event handler) ONLY if ListView's item view has no focusables. So, you need to override

@Override
public boolean hasFocusable() {
    return false;
}

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

in a view that you add to ListView. (in my case that is a layout that contains textView)

也可以使用 setOnClickLIstener 的这一观点。 所以,这些是黑客,但他们的工作。

or you can use setOnClickLIstener for that view. so, these are hacks, but they work.

这篇关于ListView控件:TextView中与LinkMovementMethod使得列表项目无法点击?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆