Перерисовать одну строку в списке

Можно ли перерисовать одну строку в ListView? У меня есть ListView со строками LinearLayout s. Я слушаю изменение предпочтений, и иногда мне нужно изменить только один View внутри LinearLayout одной строки. Есть ли способ перерисовать эту строку без вызова listview.notifyDatasetChanged()?

Я попытался вызвать view.invalidate() в представлении (внутри LinearLayout), но он не перерисовывает строку.

Ответ 1

Поскольку Romain Guy объяснил какое-то время в течение сеанса ввода/вывода Google, наиболее эффективным способом для обновления только одного вида в представлении списка есть что-то вроде следующего (это одно обновление всех данных 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");

В коде, которому мы доверяем.

Ответ 2

view.invalidate() не работал у меня. Но это работает как шарм:

предположите, что вы обновляете позицию "position" в строке. if избегать странных перерисовывающих вещей, таких как текстовые танцы, когда вы обновление строки, которая не находится на экране.

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

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

Ответ 3

Ромен Гай ответил на этот вопрос в "Google IO 2010 Мир ListView" Видео в то время, когда задавался этот вопрос: http://www.youtube.com/watch?feature=player_detailpage&v=wDBM6wVEO70#t=3149s

Итак, согласно Роменину Гаю, это должно сработать, и я думаю, мы можем ему доверять.

Причина, по которой ваше представление не перерисовывается, немного таинственно. Возможно, попробуйте отключить все параметры кеша, доступные в ListView

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

Ответ 4

Поместите некоторый тег в строку, которую вы хотите обновить. Если вы хотите перерисовать этот конкретный вид или строку, выполните

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

а затем

View v = lv.findViewWithTag(tagobject);

а затем вы делаете все, что хотите, с видом.