Подтвердить что ты не робот

RecyclerView, StaggeredGridLayoutManager Обновить ошибку

Я использовал библиотеку поддержки v7-21, а RecyclerView отображается неправильно. GridLayoutManager и LinearLayoutManager ОК. Проблема возникает только в том случае, когда в StaggeredGridLayoutManager я загружаю DataSet, а затем обновляю данные. Обновление данных работает нормально, но вид RecyclerView существует вне экрана.

Кто-нибудь знает, как его исправить?

4b9b3361

Ответ 1

Обновлено 2015-01-04 (внизу)

У меня есть пример проекта, демонстрирующий это на https://github.com/dbleicher/recyclerview-grid-quickreturn. Но вот несколько подробностей, которые могут вам помочь.

Когда вы добавляете/удаляете элемент в RecyclerView, вы должны вызвать notifyItemInserted/notifyItemRemoved, чтобы адаптер сказал менеджеру макета повторно развернуть только затронутые виды. Например, в адаптере:

public void addItemAtPosition(int position, String item) {
    myDataset.add(position, item);
    mAdapter.notifyItemInserted(position);        
}

Если вы вызываете этот метод для добавления представления, и представление отображается на экране, SGLM, похоже, работает как ожидалось, вставляя и настраивая макет. Если, однако, вы просматриваете верхнюю часть списка и добавляете элемент в нулевой позиции, представление создается за пределами экрана (и вы его не увидите). Вы можете перейти к этому представлению с помощью следующего кода:

public void addItemAtPosition(int position, String item) {
    myDataset.add(position, item);
    mAdapter.notifyItemInserted(position);
    mSGLM.scrollToPosition(position);
}

Есть (IMHO) ошибка в StaggeredGridLayoutManager, которая отображается с добавлением элементов "за кадром". Согласно комментариям yiğit боярина в этой теме https://plus.google.com/u/1/111532428576115387787/posts/6xxayUBz2iV

"... если элемент добавлен за пределы, менеджер макетов не заботится"

И здесь, где появляется ошибка. С SGLM существует проблема синхронизации с , когда происходит повторная компоновка. В моем примере кода (ссылка выше) у меня есть ItemDecorator, который добавляет маркер к самому верхнему элементу, чтобы они не были закрыты панелью инструментов. При использовании вышеприведенного кода макет неправильно сохраняет этот запас на элементе, который перемещается "вниз" на экране при вставке нового элемента (ов). Облом.

Здесь макет перед добавлением вверху: Layout before adding at top

Здесь макет, демонстрирующий ошибку после добавления элемента вверху: Bad layout

Существует обходное решение, но это несколько поражает цель использования RecyclerView. В принципе, если вы просто вызываете notifyDataSetChanged после добавления/удаления, это приведет к тому, что SGLM сделает недействительным весь макет. Это не оптимально с точки зрения эффективности, но это приводит к правильной компоновке. Используя следующий код:

public void addItemAtPosition(int position, String item) {
    myDataset.add(position, item);
    mAdapter.notifyDataSetChanged();  // Should NOT do this, but it works!
    mSGLM.scrollToPosition(position);
}

Приведёт к правильной компоновке после добавления: Proper layout result

Надеюсь, что это поможет.

Обновление: 2014-01-04

Как отмечено в комментариях, еще один способ обхода - вызвать invalidateItemDecorations() в recyclerview после выполнения вставки. Прямо сейчас, кажется, что это происходит сразу после того, как вставка проигнорирует этот вызов (возможно, потому, что пропуск макета уже запущен). Если кто-то ненадолго отменил вызов, он, похоже, работает:

public void addItemAtPosition(int position, String item) {
    myDataset.add(position, item);
    mAdapter.notifyItemInserted(position);
    mSGLM.scrollToPosition(position);

    // Items added to the top row? Better invalidate the decorator.
    // Delay to ensure that the previous layout pass has completed.
    if (position < columnCount) {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mRecycler.invalidateItemDecorations();
            }
        }, 300);
    }
}

Ответ 2

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