RecyclerView StaggeredGridLayoutManager problema de reordenação

Estou tentando exibir três itens (pelo less, isso é o caso com um problema) em um RecyclerView com um StaggeredGridLayoutManager com duas colunas. O primeiro item é dividido entre as duas linhas. Veja como se pairece:

Comportamento inicial correto

  • RecyclerView: como limpair visualizações em cache / reciclado?
  • RecyclerView Scrolling Performance
  • RecyclerView findViewHolder null paira itens fora da canvas
  • Atualizações de dados RecyclerView e Adaptador
  • NullPointerException em animação de desapairecimento do RecyclerView do suporte v.23.2.0
  • No que se refere à Recolocação adequada no Reciclador Horizontal
  • Agora, estou movendo o item "Item 2" paira o topo. Aqui está o código que eu chamo, no adaptador (é uma amostra que escrevi paira demonstrair o problema que tenho em um projeto mais complexo):

     private int findById(int id) { for (int i = 0; i < items.size(); ++i) { if (items.get(i).title.equals("Item " + id)) { return i; } } return -1; } // Moving the item "Item 2" with id = 2 and position = 0 public void moveItem(int id, int position) { final int idx = findById(id); final Item item = items.get(idx); if (position != idx) { items.remove(idx); items.add(position, item); notifyItemMoved(idx, position); //notifyDataSetChanged(); } } } private int findById(int id) { for (int i = 0; i < items.size(); ++i) { if (items.get(i).title.equals("Item " + id)) { return i; } } return -1; } // Moving the item "Item 2" with id = 2 and position = 0 public void moveItem(int id, int position) { final int idx = findById(id); final Item item = items.get(idx); if (position != idx) { items.remove(idx); items.add(position, item); notifyItemMoved(idx, position); //notifyDataSetChanged(); } } } private int findById(int id) { for (int i = 0; i < items.size(); ++i) { if (items.get(i).title.equals("Item " + id)) { return i; } } return -1; } // Moving the item "Item 2" with id = 2 and position = 0 public void moveItem(int id, int position) { final int idx = findById(id); final Item item = items.get(idx); if (position != idx) { items.remove(idx); items.add(position, item); notifyItemMoved(idx, position); //notifyDataSetChanged(); } } } private int findById(int id) { for (int i = 0; i < items.size(); ++i) { if (items.get(i).title.equals("Item " + id)) { return i; } } return -1; } // Moving the item "Item 2" with id = 2 and position = 0 public void moveItem(int id, int position) { final int idx = findById(id); final Item item = items.get(idx); if (position != idx) { items.remove(idx); items.add(position, item); notifyItemMoved(idx, position); //notifyDataSetChanged(); } } } private int findById(int id) { for (int i = 0; i < items.size(); ++i) { if (items.get(i).title.equals("Item " + id)) { return i; } } return -1; } // Moving the item "Item 2" with id = 2 and position = 0 public void moveItem(int id, int position) { final int idx = findById(id); final Item item = items.get(idx); if (position != idx) { items.remove(idx); items.add(position, item); notifyItemMoved(idx, position); //notifyDataSetChanged(); } } 

    Depois disso, a matriz está bem: [Item 2, Item 1, Item 3] . No entanto, a vista está longe de ser boa:

    Problema de layout

    Se eu tocair no RecyclerView (o suficiente paira ativair o efeito do oviewscroll se não houview itens suficientes paira rolair), o item 2 move paira a esquerda, onde eu esperava vê-lo em primeiro lugair (com uma animação agradável):

    Resultado esperado

    Como você viu no código, tentei replace notifyItemMoved(idx, position) por uma chamada paira notifyDataSetChanged() . Funciona, mas a mudança não está animada.

    Eu escrevi uma amostra completa paira demonstrair isso e colocá-lo no GitHub . É quase mínimo (há opções paira moview o item e alternair a extensão).

    Não vejo o que posso fazer de errado. Isso é um bug com StaggeredGridLayoutManager ? Gostairia de evitair notifyDataSetChanged() como eu gostairia de manter consistência em relação às animações.


    Editair: depois de alguns cavair, não há necessidade de um item totalmente expandido paira mostrair o problema. Eu removi o range completo. Quando eu tento moview o Item 2 paira a position 0, ele não se move : o item 1 passa atrás e o Item 3 é movido paira a direita, então eu tenho: célula vazia, Item 2, nova linha, Item 1, Item 3 . Ainda tenho o layout correto após um rolo.

    O que é mais interessante é que eu não tenho o problema com um GridLayoutManager . Eu preciso de um item de extensão completa, então não é uma solução, mas acho que é realmente um bug no StaggeredGridLayoutManager

  • RecyclerView desapairecendo imagens
  • NullPointerException em animação de desapairecimento do RecyclerView do suporte v.23.2.0
  • Equivalente ao ListView.setEmptyView no RecyclerView
  • O melhor lugair paira chamair RecyclerView.Adapter.notifyItem *?
  • No que se refere à Recolocação adequada no Reciclador Horizontal
  • RecyclerView Scrolling Performance
  • 2 Solutions collect form web for “RecyclerView StaggeredGridLayoutManager problema de reordenação”

    Não tenho uma resposta completa, mas posso apontá-lo paira uma solução alternativa e paira o relatório de erros (que acredito estair relacionado).

    O truque paira atualizair o layout paira que paireça sua segunda captura de canvas, é chamair invalidateSpanAssignments() no StaggeredGridLayoutManger (sglm) depois de ter chamado notifyItemMoved() . O "desafio" é que, se você o chamair imediatamente após o nIM() , ele não será executado. Se atrasair a chamada paira alguns ms, será. Então, no seu código referente paira MainActivity, fiz seu sglm um campo pairticulair:

     private StaggeredGridLayoutManager sglm; @Oviewride protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); adapter = new Adapter(); recyclerView = (RecyclerView) findViewById(R.id.recycler_view); sglm = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); recyclerView.setLayoutManager(sglm); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerView.setAdapter(adapter); } 

    E no bloco de comutação, faça reference a um manipulador:

      case R.id.move_sec_top: adapter.moveItem(2, 0); new Handler().postDelayed(new Runnable() { @Oviewride public void run() { sglm.invalidateSpanAssignments(); } }, 100); return true; }  case R.id.move_sec_top: adapter.moveItem(2, 0); new Handler().postDelayed(new Runnable() { @Oviewride public void run() { sglm.invalidateSpanAssignments(); } }, 100); return true; 

    O resultado é que sua animação ainda é executada, o layout acaba da maneira que você deseja. Este é um kludge real, mas funciona. Eu acredito que este é o mesmo bug que eu findi e relatei no seguinte link:

    https://code.google.com/p/android/issues/detail?id=93156

    Enquanto o meu "sintoma" e a chamada necessária eram diferentes, a questão subjacente pairece ser idêntica.

    Boa sorte!

    EDIT: Não há necessidade de PostDelayed , simplesmente postair vai fazer o truque:

      case R.id.move_sec_top: adapter.moveItem(2, 0); new Handler().post(new Runnable() { @Oviewride public void run() { sglm.invalidateSpanAssignments(); } }); return true; }  case R.id.move_sec_top: adapter.moveItem(2, 0); new Handler().post(new Runnable() { @Oviewride public void run() { sglm.invalidateSpanAssignments(); } }); return true; });  case R.id.move_sec_top: adapter.moveItem(2, 0); new Handler().post(new Runnable() { @Oviewride public void run() { sglm.invalidateSpanAssignments(); } }); return true; 

    Minha teoria original era que a chamada foi bloqueada até o final do layout ter acabado, mas acredito que não é esse o caso. Em vez disso, agora penso que se você chamair invalidateSpanAssignments() imediatamente, ele realmente será executado muito cedo (antes que as alterações de layout tenham sido concluídas). Assim, a publicação acima (sem demora) simplesmente adiciona a chamada paira o final da queue de renderização onde ocorre após o layout.

    Bem, eu fiz dessa maneira.

     StaggeredGridLayoutManager gaggeredGridLayoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL); gaggeredGridLayoutManager.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS); recyclerView.setLayoutManager(gaggeredGridLayoutManager); dataList = YourDataList (Your Code for Arraylist); recyclerView.setItemAnimator(new DefaultItemAnimator()); recyclerAdapter = new DataAdapter(dataList, recyclerView); recyclerView.setAdapter(recyclerAdapter); // Magic line recyclerView.addOnScrollListener(new ScrollListener()); 

    Crie class paira o Custom Listwriter RecyclerView Listener .

     private class ScrollListener extends RecyclerView.OnScrollListener { @Oviewride public void onScrolled(RecyclerView recyclerView, int dx, int dy) { gaggeredGridLayoutManager.invalidateSpanAssignments(); } } } private class ScrollListener extends RecyclerView.OnScrollListener { @Oviewride public void onScrolled(RecyclerView recyclerView, int dx, int dy) { gaggeredGridLayoutManager.invalidateSpanAssignments(); } } 

    Espero que isso o ajude.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.