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

7 浏览
0 Comments

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

我的目标是创建一个包含如下消息的列表:

这是用户写的消息,它会很好地换行。就像这样。

我有以下内容:

ListView R.layout.list_item:


适配器会填充上述布局并执行以下操作:

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类:

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

问题:

点击列表项时不会显示toast。只有点击用户名才会显示toast。

我猜测setMovementMethod(LinkMovementMethod.getInstance());使TextView可点击。所以,列表项本身不再被点击。

如何使列表项再次可点击,并具有相同的功能?

0
0 Comments

ListView中的TextView使用LinkMovementMethod后,列表项不可点击的原因可能是因为LinkMovementMethod会覆盖ListView的点击事件,导致无法触发列表项的点击事件。解决方法是使用自定义的OnTouchListener,在触摸事件中模拟LinkMovementMethod的点击功能,以实现点击链接和点击列表项的双重功能。

具体的解决方法如下:

1. 在适配器的getView()方法中为TextView设置自定义的OnTouchListener。

2. 在OnTouchListener的onTouch方法中,获取点击事件的坐标,并根据坐标计算出点击位置在TextView中的行数和偏移量。

3. 使用getSpans方法获取点击位置处的ClickableSpan对象数组。

4. 如果获取到的ClickableSpan数组不为空,说明点击位置处有可点击的链接,根据点击事件的类型执行ClickableSpan的onClick方法,并返回true表示已处理点击事件。

5. 如果获取到的ClickableSpan数组为空,说明点击位置处没有可点击的链接,返回false表示未处理点击事件。

代码如下:

myTextView.setOnTouchListener(new OnTouchListener() {
    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;
    }
});

需要注意的是,这种解决方法可能会导致在ClickableSpan外部点击区域也被认为是点击了ClickableSpan,因此可以在点击事件中先判断点击位置是否在ClickableSpan的范围内,再决定是否处理点击事件。

此外,可能会出现警告信息"'onTouch should call View#performClick when a click is detected'",可以忽略该警告或在onTouch方法中添加View的performClick方法以消除警告。

总结起来,解决ListView中TextView使用LinkMovementMethod导致列表项不可点击的问题的方法是使用自定义的OnTouchListener来模拟LinkMovementMethod的点击功能,并在触摸事件中判断点击位置和处理点击事件。

0
0 Comments

这篇文章将讨论一个关于ListView中的TextView使用LinkMovementMethod导致列表项不可点击的问题,以及解决方法。

问题的原因是,当TextView中使用LinkMovementMethod时,它会捕捉到触摸事件,并处理链接的点击事件。这会导致ListView无法捕捉到触摸事件,从而使列表项无法点击。

解决方法是修改ListView的适配器,通过设置ViewGroup的descendantFocusability属性为FOCUS_BLOCK_DESCENDANTS,来阻止TextView捕捉到触摸事件。这样,列表项就可以正常点击了。

以下是解决方法的示例代码:

private class YourListadapter extends BaseAdapter {
    public View getView(int position, View convertView, ViewGroup parent) {
        ((ViewGroup)convertView).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
        return convertView;
    }
}

上述代码将ListView的适配器中的getView方法进行了修改,在获取视图的时候,通过设置convertView的descendantFocusability属性为FOCUS_BLOCK_DESCENDANTS来阻止TextView捕捉到触摸事件。

此外,还可以通过在XML布局文件中设置descendantFocusability属性来解决该问题。在ListView的布局中,设置android:descendantFocusability="blocksDescendants"即可。


通过以上方法,可以解决TextView使用LinkMovementMethod导致列表项不可点击的问题。

0
0 Comments

问题的原因是当调用setMovementMethod或setKeyListener时,TextView会自动设置为可点击、可长按、可聚焦。第一个问题是当一个View可点击时,它会消耗ACTION_UP事件,即在onTouchEvent方法中返回true。为了解决这个问题,可以在onTouchEvent方法中只在用户实际点击链接时返回true。但是LinkMovementMethod无法告诉我们用户是否实际点击了链接,它在onTouch方法中无论用户点击链接还是其他情况都返回true。为了解决这个问题,可以通过在TextViewFixTouchConsume类中设置一个标志位来判断用户是否实际点击了链接,并在onTouchEvent方法中返回这个标志位。

第三个问题是ListView在performClick方法中只有在ListView的item view没有可聚焦的子元素时才调用onItemClick事件处理程序。为了解决这个问题,需要在添加到ListView中的view中重写hasFocusable方法,将其返回false,或者可以为该view设置setOnClickListener方法。

所以,解决该问题的方法是:创建一个TextViewFixTouchConsume类继承自TextView,在该类中重写onTouchEvent方法和hasFocusable方法,同时创建一个LocalLinkMovementMethod类继承自LinkMovementMethod,并在其中重写onTouchEvent方法。然后,在需要使用这个功能的TextView上调用setMovementMethod方法并传入LocalLinkMovementMethod.getInstance()。

但是需要注意的是,这个解决方法也会带来另一个问题,即长按操作会在点击列表项后立即触发,而不是需要按住一段时间才触发。

此外,还有其他一些问题需要注意,比如在某些设备上可能会抛出异常,解决方法是使用clear版本的Android 5.0,还有可能会出现调用setFocusable(false)无效的情况,因为TextView会自动将其设置为可聚焦。

0