【问题标题】:Link spans are lost from ListView's convertViewListView 的 convertView 中的链接跨度丢失
【发布时间】:2014-01-17 10:24:06
【问题描述】:

为什么滚动时ListView 中的链接会丢失?从调试中可以清楚地看出,跨度不会第二次添加到来自convertViewTextView

这是一段从适配器的getView 调用的代码。

    ...
    String body = MyItemDetails.getBody(); // String to linkify

    final Spannable spannable = MyCustomUri.addHashtagSpans(context, body);
    viewHolder.textView.setText(spannable);

    viewHolder.textView.setTextIsSelectable(true); // adds additional spans
    viewHolder.textView.setMovementMethod(ArrowKeyMovementMethod.getInstance());
    viewHolder.textView.setAutoLinkMask(Linkify.WEB_URLS);
    ...

MyCustomUri.addHashtagSpans() 创建一个 SpannableStringMyCustomSpan 扩展 URLSpan

问题是当我在ListView 中上下滚动时,链接丢失了。而当屏幕第一次打开时,它设置正确。

现在我通过禁用 convertView 的重用做了一个肮脏的修复:( 有什么想法可以更好地解决这个问题吗?

【问题讨论】:

  • 请发布您的 getView 方法的完整代码(如果您正在扩展 CursorAdapter,请发布 bindView 和 newView)。

标签: android listview textview linkify spannablestring


【解决方案1】:

在将 textview 的数据写入包裹以进行保留时,一些可扩展信息可能会丢失。

请参阅TextView.onSaveInstanceState()TextView.onRestoreInstanceState()TextView.SavedState

确定 android 将保留哪些内容和不保留哪些内容通常非常令人沮丧。我经常只是在我的视图上setSaveEnabled(false) 来禁用基本小部件的不可预测的默认行为。

另外,viewholder 模式仅用于保留视图/布局实例层次结构。为了让您不必在每个getView() 上膨胀或查找您的视图。从getView() 呈现视图数据时,您始终有责任更新视图数据。

您不需要完全禁用 viewholder 模式,只需每隔getView() 更新一次文本,您可能已经这样做了。

【讨论】:

  • 试过setSaveEnabled(false),但没有帮助:(
  • 是的,这只是旁白。不会直接解决问题
  • 重点是不能一直依赖android来保持view状态,应该养成自己动手的习惯。
  • 那么有没有办法重置TextView的状态?
  • 当然,TextView.setText()。从SavedState 类中,我们可以看到这几乎就是所有保留的内容。
【解决方案2】:

你好使用这个自定义类

public class MyCustomSpannable extends ClickableSpan {
String Url;
Context mContext;

public MyCustomSpannable(String Url, Context context) {
    this.Url = Url;
    mContext = context;
}

@Override
public void updateDrawState(TextPaint ds) {
    // Customize your Text Look if required
    ds.setColor(mContext.getResources().getColor(R.color.red_text));
    ds.setFakeBoldText(true);
    // ds.setStrikeThruText(true);
    ds.setTypeface(CommonFunctios.getfontNormal(mContext));
    // ds.setUnderlineText(true);
    // ds.setShadowLayer(10, 1, 1, Color.WHITE);
    // ds.setTextSize(15);
}

@Override
public void onClick(View widget) {
}

public String getUrl() {
    return Url;
}
}

在适配器中用这个替换你的代码

String text = holder.txt_terms.getText().toString();
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(text);
MyCustomSpannable customSpannable = new MyCustomSpannable(text,
            mcontext) {

        @Override
        public void onClick(View widget) {
            Log.e("on click", "message");
            ((OpticalOffersActivity) mcontext).callDialogBox(position);
        }
    };
    stringBuilder.setSpan(customSpannable, 0, text.length(),
            Spannable.SPAN_INCLUSIVE_INCLUSIVE);

    holder.txt_terms.setText(stringBuilder, BufferType.SPANNABLE.SPANNABLE);
    holder.txt_terms.setMovementMethod(LinkMovementMethod.getInstance());

希望对你有所帮助。

【讨论】:

    【解决方案3】:
    if(convertView==null)
        {
    
            convertView.setTag(holder);
        }
    else
        {
                holder = (ViewHolder)convertView.getTag();
        }
    
    
    
    
     ...
            String body = MyItemDetails.getBody(); // String to linkify
    
            final Spannable spannable = MyCustomUri.addHashtagSpans(context, body);
            viewHolder.textView.setText(spannable);
    
            viewHolder.textView.setTextIsSelectable(true); // adds additional spans
            viewHolder.textView.setMovementMethod(ArrowKeyMovementMethod.getInstance());
            viewHolder.textView.setAutoLinkMask(Linkify.WEB_URLS);
            ...
    

    该可扩展代码必须放在 getView() 方法中的 if-else 循环之外,就像我在上面的代码中所做的那样。

    【讨论】:

    • 没错,我已经在 if-else 块之外放置了可扩展的代码。重用 convertView 时会出现问题。 MyCustomUri 跨度不会第二次添加。
    【解决方案4】:

    这里有几个问题,所以让我一次解决一个。您直接询问的问题(链接消失)是一个副作用,即TextView 中的自动链接行为在您手动将自己的跨度添加到文本时不一定能很好地工作......最好不要使用它。移除setAutoLinkMask() 触发器,消失的链接问题就会消失。

    相反,您可以使用Linkify 轻松地将相同的网络链接行为直接添加到您的文本跨度中。但是,这只是您的问题的一部分。您选择的MovementMethod 与可点击链接并不真正兼容。它(部分)现在在您的代码中工作的原因是因为自动链接掩码导致视图的MovementMethod 在引擎盖下被秘密按摩到LinkMovementMethod...然后在视图被回收后被重置.我通常使用的模式(应用于您的代码示例)是:

    final Spannable spannable = MyCustomUri.addHashtagSpans(context, body);
    Linkify.addLinks(spannable, Linkify.WEB_URLS);
    viewHolder.textView.setText(spannable);
    
    addLinkMovementMethod(textView);
    

    addLinkMovementMethod() 是我的助手,看起来像这样:

    private void addLinkMovementMethod(TextView t) {
        MovementMethod m = t.getMovementMethod();
    
        if ((m == null) || !(m instanceof LinkMovementMethod)) {
            if (t.getLinksClickable()) {
                t.setMovementMethod(LinkMovementMethod.getInstance());
            }
        }
    }
    

    如果没有必要,这只是避免在每个视图回收时重置值。前面的代码块将为您提供正确点击且永不消失的链接...

    但是,根据您调用的方法,我猜测您还试图使列表中的链接文本成为可选(例如,调用 setTextIsSelectable() 并选择 ArrowKeyMovementMethod)。由于我上面讨论的MovementMethod 问题,这变得有点棘手。为了创建一个同时支持链接点击和文本选择的MovementMethod,我将引导您查看此主题的现有 SO 帖子,其中包括您需要进行的自定义的示例代码:Can a TextView be selectable AND contain links?

    【讨论】:

    • 这看起来很有希望的解决方案。会试试的。
    猜你喜欢
    • 2012-10-03
    • 1970-01-01
    • 2017-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-20
    相关资源
    最近更新 更多