在列表视图中重绘单行

发布于 2024-09-30 16:44:21 字数 296 浏览 5 评论 0原文

是否可以在 ListView 中重绘单行?我有一个 ListView ,其中的行是 LinearLayout 。我监听首选项更改,有时我只需要更改单行的 LinearLayout 内的一个 View。有没有办法让它重绘该行而不调用listview.notifyDatasetChanged()

我尝试在视图上调用 view.invalidate() (在 LinearLayout 内),但它不会重绘行。

Is it possible to redraw a single row in a ListView? I have a ListView with rows that are LinearLayouts. I listen to a preference change and sometimes I need to change just one View inside the LinearLayout of a single row. Is there a way to make it redraw that row without calling listview.notifyDatasetChanged()?

I've tried calling view.invalidate() on the view (inside the LinearLayout) but it doesn't redraw the row.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

温暖的光 2024-10-07 16:44:21

正如 Romain Guy 不久前解释的那样。 google.com/events/io/2010/sessions/world-of-listview-android.html">Google I/O 会话,仅更新列表视图中的一个视图的最有效方法类似于以下(此更新整个 View 数据):

ListView list = getListView();
int start = list.getFirstVisiblePosition();
for(int i=start, j=list.getLastVisiblePosition();i<=j;i++)
    if(target==list.getItemAtPosition(i)){
        View view = list.getChildAt(i-start);
        list.getAdapter().getView(i, view, list);
        break;
    }

假设 target 是适配器的一项。

此代码检索 ListView,然后浏览当前显示的视图,将您要查找的 target 项与每个显示的视图项进行比较,如果您的目标在其中,则获取封闭视图并在该视图上执行适配器 getView() 来刷新显示。

附带说明一下,invalidate() 并不像某些人期望的那样工作,也不会像 getView() 那样刷新视图,notifyDataSetChanged() 将重建整个列表并最终为每个显示的项目调用 getview() ,并且 invalidateViews() 也会影响一堆。

最后一件事,如果只需要更改行视图的子视图而不是像 getView 那样更改整行,也可以获得额外的性能。在这种情况下,以下代码可以替换 list.getAdapter().getView(i, view, list); (更改 TextView 文本的示例):

((TextView)view.findViewById(R.id.myid)).setText("some new text");

在代码中,我们相信。

As Romain Guy explained a while back during the Google I/O session, the most efficient way to only update one view in a list view is something like the following (this one update the whole View data):

ListView list = getListView();
int start = list.getFirstVisiblePosition();
for(int i=start, j=list.getLastVisiblePosition();i<=j;i++)
    if(target==list.getItemAtPosition(i)){
        View view = list.getChildAt(i-start);
        list.getAdapter().getView(i, view, list);
        break;
    }

Assuming target is one item of the adapter.

This code retrieve the ListView, then browse the currently shown views, compare the target item you are looking for with each displayed view items, and if your target is among those, get the enclosing view and execute the adapter getView() on that view to refresh the display.

As a side note invalidate() doesn't work like some people expect and will not refresh the view like getView() does, notifyDataSetChanged() will rebuild the whole list and end up calling getview() for every displayed items and invalidateViews() will also affect a bunch.

One last thing, one can also get extra performance if he only needs to change a child of a row view and not the whole row like getView does. In that case, the following code can replace list.getAdapter().getView(i, view, list); (example to change a TextView text):

((TextView)view.findViewById(R.id.myid)).setText("some new text");

In code we trust.

┾廆蒐ゝ 2024-10-07 16:44:21

view.invalidate() 对我不起作用。但这就像一个魅力:

假设您正在更新行中的位置“position”。
if 避免奇怪的重画内容,比如当你
更新不在屏幕中的行。

            if (position >= listView.getFirstVisiblePosition()
                && position <= listView.getLastVisiblePosition()) {

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            listView.invalidateViews();
                        }
                    });
            }

The view.invalidate() didn't work for me. But this works like a charm:

supose you are updating the position "position" in the row.
The if avoid weird redraws stuffs, like text dancing when you are
updating a row that are not in the screen.

            if (position >= listView.getFirstVisiblePosition()
                && position <= listView.getLastVisiblePosition()) {

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            listView.invalidateViews();
                        }
                    });
            }
┊风居住的梦幻卍 2024-10-07 16:44:21

Romain Guy 在“Google IO 2010 The world of ListView”中回答了这个问题
提出此问题的确切时间的视频:http:// www.youtube.com/watch?feature=player_detailpage&v=wDBM6wVEO70#t=3149s

所以根据 Romain Guy 的说法,这应该有效,我认为我们可以信任他。

你的视图没有重绘的原因有点神秘。
也许尝试禁用 listView 中可用的所有缓存选项

setAnimationCacheEnabled(false);
setScrollingCacheEnabled(false);
setChildrenDrawingCacheEnabled(false);
setChildrenDrawnWithCacheEnabled(false);

Romain Guy answered to this question at "Google IO 2010 The world of ListView"
Video at the exact time where this question was asked : http://www.youtube.com/watch?feature=player_detailpage&v=wDBM6wVEO70#t=3149s

So according to Romain Guy, that should work, and I think we can trust him.

The reason why your view is not redrawn is a bit mysterious.
Maybe try disabling all cache options available in listView

setAnimationCacheEnabled(false);
setScrollingCacheEnabled(false);
setChildrenDrawingCacheEnabled(false);
setChildrenDrawnWithCacheEnabled(false);
明媚殇 2024-10-07 16:44:21

在要更新的行上放置一些标签。
当您想要重绘该特定视图或行时,然后执行

ListView lv = (ListView)findViewById(....)

此操作,

View v = lv.findViewWithTag(tagobject);

然后对视图执行任何您想要的操作。

Put some tag on the row that you want to update.
When you want to redraw that specific view or row then do

ListView lv = (ListView)findViewById(....)

and then

View v = lv.findViewWithTag(tagobject);

and then you do whatever you want with the view.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文