列表视图中的动态视图

时间:2013-04-04 10:39:08

标签: android android-listview

我正在制作一种音乐播放器,它有一个带有歌曲的列表视图(在当前播放的歌曲附近有进度条)

重要的是我有一个可以从外部(在某个处理程序中)更改视图的项目

 public View getView(int i, View convertView, ViewGroup viewGroup) {
   RelativeLayout result;

        if (convertView == null) {
            result = (RelativeLayout) inflater.inflate(R.layout.list_item, viewGroup, false);
        } else {
            result = (RelativeLayout) convertView;
        }

        ...
        ProgressBar progressBar = result.findViewById(R.id.progressBar)
        ...

        if (i == currentSong) {
           // saving to instance variable
           this.currentlyPlayingProgressBar = progressBar;
        } else {
           progressBar.setVisibility(View.GONE);
        }
        ...       
        return result;
}

(代码已更改为专注于我的问题)

Btw currentSong可以从外部更改,在这种情况下调用adapter.notifyDataSetChanged()。

我似乎错误地使用了listView,但我不知道更好的方法。

主要问题是我需要链接到视图才能更改它们。 我可以获得它们的唯一方法是使用getView方法,只有谷歌开发人员可以解释这种方式重用这些视图=(


第一个问题

这一切都发生在Fragment中,它只是viewPager的一部分。当用户滚动这个片段,然后向后滚动然后调用getView方法时,里面有一些奇怪的对象。我用这个无效值覆盖currentPlayingProgressBar。这导致我的状态栏冻结。 (它开始更新错误的视图)

我不知道它是哪种观点..


第二个问题

我正在重复使用列表项,这意味着当用户向下滚动列表视图时 - 有时候他实际上会获得具有相同progressBar的相同列表项。 这个progressBar必须是隐形的,但它不是(我认为这都是因为我从外面使用了currentPlayingProgressBar)

提前致谢。

2 个答案:

答案 0 :(得分:0)

您可以通过两种方式执行此操作:

1)notifyDataSetChanged,它只重置整个ListView并将所有可见列表项再次分配给视图。 notifyDataSetChanged非常昂贵,因为它会重新创建整个列表和视图层次结构,测量布局等,这很慢。对于单个列表项的频繁更新,例如进度条更改,这是过度的。

2)查找特定列表视图项的视图,并仅更新该视图。我们将专注于这种方法。

首先,您需要以某种方式识别哪个列表视图包含哪个列表项。常见的方法是在View.setTag中使用Adapter.getView,其中setTag参数是您选择的对象,可能与您为Adapter.getItem返回的项目相同。 因此,稍后您将知道哪个ListView子视图具有指定的项目。

假设您要更新ListView中显示的特定项目,您必须遍历ListView子视图以查找哪个视图显示您的项目:

Object myItem = ...;
for(int i = list.getChildCount(); --i>=0; ){
     View v = list.getChildAt(i);
     Object tag = v.getTag();
     if(tag==myItem) {
        // found, rebind this item
        bindItemToView(myItem, v);
        break;
     }
  }

您必须预期ListView当前可能不会显示您的列表项(滚动)。

从上面的代码中可以看到它调用了bindItemToView,它是将项目绑定到列表视图的函数。你可能会调用相同的函数在Adapter.getView中设置项目视图。

您还可以进一步优化它,假设您只想更新ProgressBar,然后不要调用bindItemToView,而是在listitem视图中更新ProgressBar(findViewById,设置值)。

提示:使用ViewHolder approach可以使其更加优化。然后setTag将不包含您的项目对象,而是您的ViewHolder对象。

答案 1 :(得分:0)

@Pointer null也给出了非常有用的方法,但是在你的情况下我认为你正在更新不可见的列表,在这种情况下你必须像适应列表索引那样设置适配器的标签并且相应检查是否列表项存在于最后一个可见项或第一个可见项之间,然后更新它,否则不要更新..