【问题标题】:ListView reusing views when ... I don't want it toListView 重用视图时......我不希望它
【发布时间】:2011-08-03 03:57:58
【问题描述】:

我有一个ListView,每个item 都包含一个ToggleButton。在我切换它然后向上或向下滚动之后,ListView 正在回收视图,因此其他一些正在镜像ToggleButton 的选中状态。我不想要这个。如何预防?

【问题讨论】:

  • 发布你的 getview() 方法有问题

标签: android


【解决方案1】:

将这两种方法添加到您的适配器中。

@Override

public int getViewTypeCount() {                 

    return getCount();
}

@Override
public int getItemViewType(int position) {

    return position;
}

【讨论】:

  • 这太可怕了。 @RomainGuy 如果偶然发现这一点,他可能会流下血泪!您基本上是在告诉适配器永远不要回收视图。这将导致用户界面迟缓,缺乏响应能力。人,请不要使用这个!为了您的用户!
  • 这样做相当于不使用数组列表,只使用 ScrollView 并调用 .addView 将所有行都扔到那里...如果行中还有图像 - OutOfMemory 异常只是在拐角处……
  • 这确实会禁用视图回收!!而这正是我所需要的!!就我而言,ListView 只有 5-7 个单元格,但布局和内容完全不同。回收视图造成了巨大的混乱......非常感谢这个调整!
  • 我不知道...我有一个列表,其中最多包含 60 个 youtube 缩略图、标题、持续时间以及可能用于下载 PDF 文件的链接。为了咯咯笑,为了测试这一点,我使用这种方法将其中的 100 多个放在一个列表中。没有一个问题。滚动超级流畅。我尚未在旧设备上对此进行测试,但这似乎是一个很好的解决方案。
  • 嗯,请谨慎使用,仅:仅当您知道 100% 列表很小且已知 ui on view 使用低内存时才适用;
【解决方案2】:

Android 会出于性能目的回收列表项。如果您希望 ListView 平滑滚动,强烈建议重用它们。

对于每个列表项,调用适配器的getView 函数。在那里,您必须为 ListView 要求的项目分配值。

看看这个例子:

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    ViewHolder holder = null;

    if ( convertView == null )
    {
        /* There is no view at this position, we create a new one. 
           In this case by inflating an xml layout */
        convertView = mInflater.inflate(R.layout.listview_item, null);  
        holder = new ViewHolder();
        holder.toggleOk = (ToggleButton) convertView.findViewById( R.id.togOk );
        convertView.setTag (holder);
    }
    else
    {
        /* We recycle a View that already exists */
        holder = (ViewHolder) convertView.getTag ();
    }

    // Once we have a reference to the View we are returning, we set its values.

    // Here is where you should set the ToggleButton value for this item!!!

    holder.toggleOk.setChecked( mToggles.get( position ) );

    return convertView;
}

请注意,ViewHolder 是我们用来回收该视图的静态类。它的属性是您的列表项拥有的视图。它在您的适配器中声明。

static class ViewHolder{
    ToggleButton toggleOk;
}

mToggles 在您的适配器中被声明为私有属性,并使用这样的公共方法进行设置:

public void setToggleList( ArrayList<Boolean> list ){
        this.mToggles = list;
        notifyDataSetChanged();
    }

查看其他自定义 ListView 示例以了解更多信息。

希望对你有帮助。

【讨论】:

  • 我知道这一切。如果其中的数据发生更改,我希望 ListView 不会重用视图。
  • 我不明白你的意思。我无法想象你为什么每次都需要一个新的视图。实际上,我认为 Views 的重用是一个很棒的 Android 功能。
  • 观点很好,我并不反对重用视图的好处。但是,我尝试让每个项目的 toggleButton 保持其正确状态(选中或未选中)是否合理?
  • 好吧,如果你的 ListView 很长,不重用就意味着浪费内存。在移动设备中,您必须小心。此外,您应该将项目的状态保留在模型中而不是视图中。无论如何回答您的问题,如果您想为每个项目创建一个视图,只需在每次调用 getView 时创建它(忘记 if ... else ... 语句)。不过我不推荐它。
  • @LuxuryMode:您能否发布解决方案,您是如何解决的?我也处于同样的位置。对于每个列表视图项,它的类中有一个“日期”,我每次检查日期是否已经不在数组列表中,然后将日期添加到该列表视图项中,并将其添加到数组列表中。现在,当再次调用 getView 时,由于日期已经在日期数组列表中,它会从中删除日期,现在尽管我坚持了很多小时......你能帮忙吗?
【解决方案3】:

您可以使用HashMap 来保存您的按钮状态:

 private Map<Integer,Boolean> listMapBoolean = new HashMap<Integer,Boolean>();


 toggleButton.setOnCheckedChangeListener(new OnCheckedChangeListener() {
                    @Override
                    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                        if (isChecked) {
                            listMapBoolean.put(position, true);
                        } else {
                            listMapBoolean.put(position, false);
                        }
                    }
                });

膨胀视图后,您阅读HashMap 以查看它是否被检查:

 for (Entry<Integer, Boolean> entry : listMapBoolean.entrySet()) {
                if (entry.getKey().equals(i)) {
                    if(entry.getValue()) {
                        System.out.println("ToggleButton is checked!");
                    } else {
                        System.out.println("ToggleButton is not checked!");
                    }
                }
            }

不确定它是否对您有帮助。我在ListView 中回收我的EditText 时也遇到了问题。

【讨论】:

  • 当然,您首先需要将所有工具按钮设置为 false。
【解决方案4】:

这会使大型列表变得如此缓慢。但是在getView()里面,你可以使用:

if (listItemView == null || ((int)listItemView.getTag()!=position)) {
            listItemView = LayoutInflater.from(context).inflate(R.layout.edit_text_list_item,
                    parent, false);
}

listItemView.setTag(position);
// set inner Views data from ArrayList
...

标签是与View 关联的Object。并且您在回收时检查它是否可以回收。这使得每个列表项都被夸大了,没有任何东西会被回收。

这也应该防止从EditText 中删除ListView 中的文本,并且如果您的ListView 中有图像,还可以防止图像被重新排序或弄乱。

【讨论】:

    【解决方案5】:

    也许您应该尝试使用滚动视图和一个包含以编程方式添加到容器的子项的容器创建自己的列表视图。设置用于识别孩子的标签,或者您可以使用孩子的顺序

    【讨论】:

      猜你喜欢
      • 2013-01-30
      • 1970-01-01
      • 1970-01-01
      • 2019-05-20
      • 2016-10-11
      • 1970-01-01
      • 1970-01-01
      • 2015-02-15
      • 2016-07-25
      相关资源
      最近更新 更多