Android 列表视图:更新不可见视图或禁用回收

Android Listview: Updating invisible views or disabling recycling

我正在设计一个 android 游戏,我正在尝试使用 ListView。该列表使用一个 BaseAdapter,并填充了一个 ArrayList。当用户按下 ok 按钮时,我滚动到列表的顶部,然后遍历列表中的每个士兵。我设置了士兵的其中一个子视图的可绘制背景,使其成为显示 "hit" 或 "miss" 的短动画。我使用了 Handler.postDelayed() 以便每个动画完成之前的动画。

问题是我无法修改不可见的视图。我的列表中一次最多有 13 个士兵,但最多只能显示 5 个。因此,一旦我击中了第六名士兵,我就会因使用 ListView.getChildAt(soldierArrayIndex) 而出现空指针异常。我的解决方案是在 getChildAt() 调用之前添加 smoothScrollTo(soldierArrayIndex) 以使其可见,但问题仍然存在。

所以我的问题不完全是 "how to fix my code?"。我更想知道是否有办法禁用 ListView 所做的回收。我使用 getChildAt() 的原因是因为我需要在视图上使用 findViewById() returns,然后修改通过 ID 找到的视图。但是,如果视图从未被回收,则 getChildAt() 不会 return null。

我的另一个想法是只使用滚动视图,输入我创建的 Soldier View 的 13 个实例,然后将我当前未使用的设置为 "gone"。我唯一的问题是我不知道如何遍历这些视图。

TL;DR:如何更新当前在列表视图中不可见的视图(它们当前 "recycled")?

我认为你在这里混淆了模型和视图。

适配器视图采用通常可以访问整个数据集的适配器。因此,即使您的 ListView 只会呈现屏幕上可见的项目,您仍然应该能够通过在适配器上调用 getItem(position) 来访问屏幕外项目。

您似乎是直接在适配器上调用 getView。

我建议您不要这样做,因为这不是 AdapterView 和适配器的设计方式。相反,当模型中的某些内容发生更改(通过 notifyDataSetChanged)时,您需要向 ListView 发出指示,并将其留给 ListView 代表您调用适配器的 getView 方法。

我想象事件的顺序是这样的:

  1. 更新士兵对象
  2. 在您的适配器上调用 notifyDataSetChanged,它会告诉您的 ListView 它需要重绘内容
  3. ListView 遍历可见的 Soldier 项目,对每个项目调用 getView(int position, View convertView, ViewGroup parent)。
  4. 适配器中的 getView 实现获取指定位置的 Soldier,并确定 View 在该时间点的外观。

对于"offscreen"士兵(那些在ListView的滚动区域中不可见的士兵),ListView不需要渲染它们,所以它不会在这些位置调用getView。

但是,如果屏幕外的士兵现在滚动到视图中,ListView 将使用该士兵在数组中的位置调用适配器的 getView 方法。

最后,如果您想更细粒度地控制 AdapterView 应如何自我更新,您可以考虑 RecyclerView,因为它允许您逐项通知更改。