Passei um momento tentando descobrir uma maneira de adicionar um cabeçalho a RecyclerView
, sem êxito.
Isto é o que eu tenho até agora:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
layouManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layouManager);
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
headerPlaceHolder = inflater.inflate(R.layout.view_header_holder_medium, null, false);
layouManager.addView(headerPlaceHolder, 0);
...
}
A LayoutManager
parece ser o objeto de manipulação a disposição dos RecyclerView
itens. Como eu não poderia encontrar qualquer addHeaderView(View view)
método, eu decidi ir com o LayoutManager
's addView(View view, int position)
método e adicionar minha opinião cabeçalho na primeira posição para atuar como um cabeçalho.
E é aqui que as coisas ficam mais feias:
java.lang.NullPointerException: Attempt to read from field 'android.support.v7.widget.RecyclerView$ViewHolder android.support.v7.widget.RecyclerView$LayoutParams.mViewHolder' on a null object reference
at android.support.v7.widget.RecyclerView.getChildViewHolderInt(RecyclerView.java:2497)
at android.support.v7.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:4807)
at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:4803)
at com.mathieumaree.showz.fragments.CategoryFragment.setRecyclerView(CategoryFragment.java:231)
at com.mathieumaree.showz.fragments.CategoryFragment.access$200(CategoryFragment.java:47)
at com.mathieumaree.showz.fragments.CategoryFragment$2.success(CategoryFragment.java:201)
at com.mathieumaree.showz.fragments.CategoryFragment$2.success(CategoryFragment.java:196)
at retrofit.CallbackRunnable$1.run(CallbackRunnable.java:41)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Depois de várias NullPointerExceptions
tentativas de chamar o addView(View view)
em diferentes momentos da criação da atividade (também tentei adicionar a visualização depois que tudo estiver configurado, até os dados do adaptador), percebi que não fazia ideia se esse é o caminho certo para fazê-lo (e não parece ser).
PS: Além disso, uma solução que poderia lidar com o GridLayoutManager
além do LinearLayoutManager
seria muito apreciada!
fonte
Respostas:
Eu tive que adicionar um rodapé ao meu
RecyclerView
e aqui estou compartilhando meu snippet de código, pois achei que poderia ser útil. Verifique os comentários dentro do código para entender melhor o fluxo geral.O trecho de código acima adiciona um rodapé ao arquivo
RecyclerView
. Você pode verificar este repositório do GitHub para verificar a implementação de adicionar cabeçalho e rodapé.fonte
RecyclerView
dinamicamente. Você pode ter controle sobre cada um dos elementos do seuRecyclerView
. Por favor, olhe a seção de código para um projeto de trabalho. Espero que ajude. github.com/comeondude/dynamic-recyclerview/wikiint getItemViewType (int position)
- Retorne o tipo de exibição do item na posição para fins de reciclagem de exibição. A implementação padrão desse método retorna 0, assumindo um único tipo de visualização para o adaptador. Diferentemente dosListView
adaptadores, os tipos não precisam ser contíguos. Considere usar recursos de identificação para identificar exclusivamente os tipos de exibição de item. - Da documentação. developer.android.com/reference/android/support/v7/widget/…Muito simples de resolver !!
Eu não gosto de ter a lógica dentro do adaptador como um tipo de exibição diferente, porque toda vez que ele verifica o tipo de exibição antes de retornar a exibição. A solução abaixo evita verificações extras.
Basta adicionar a visualização de cabeçalho LinearLayout (vertical) + visualização de reciclagem + visualização de rodapé no android.support.v4.widget.NestedScrollView .
Veja isso:
Adicione esta linha de código para rolagem suave
Isso perderá todo o desempenho do RV e o RV tentará exibir todos os detentores de visualização, independentemente
layout_height
do RVUso recomendado para a lista de tamanhos pequenos, como gaveta Nav ou configurações etc.
fonte
RecyclerView
você traz - você perde a reciclagem real e a otimização que ela traz.Eu tive o mesmo problema no Lollipop e criei duas abordagens para envolver o
Recyclerview
adaptador. Um é bastante fácil de usar, mas não tenho certeza de como ele se comportará com um conjunto de dados alterado. Porque envolve seu adaptador e você precisa chamar métodos comonotifyDataSetChanged
o objeto-adaptador correto.O outro não deve ter esses problemas. Apenas deixe seu adaptador regular estender a classe, implementar os métodos abstratos e você deverá estar pronto. E aqui estão eles:
gists
new HeaderRecyclerViewAdapterV1(new RegularAdapter());
RegularAdapter extends HeaderRecyclerViewAdapterV2
HeaderRecyclerViewAdapterV1
HeaderRecyclerViewAdapterV2
Comentários e garfos apreciados. Vou usar
HeaderRecyclerViewAdapterV2
por mim mesmo e evoluir, testar e publicar as mudanças no futuro.EDIT : @OvidiuLatcu Sim, tive alguns problemas. Na verdade, parei de compensar implicitamente o cabeçalho
position - (useHeader() ? 1 : 0)
e, em vez disso, criei um método públicoint offsetPosition(int position)
para ele. Como se você definir umOnItemTouchListener
na Reciclerview, poderá interceptar o toque, obter as coordenadas x, y do toque, encontrar a visão filho correspondente e, em seguida, ligarrecyclerView.getChildPosition(...)
e sempre obterá a posição não compensada no adaptador! Isso é uma falha no código do RecyclerView, não vejo um método fácil de superar isso. É por isso que agora compenso as posições explícitas quando preciso pelo meu próprio código.fonte
Eu não tentei isso, mas eu simplesmente adicionaria 1 (ou 2, se você deseja um cabeçalho e rodapé) ao número inteiro retornado por getItemCount no seu adaptador. Você pode substituir
getItemViewType
no seu adaptador para retornar um número inteiro diferente quandoi==0
: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#getItemViewType(int)createViewHolder
é passado o número inteiro do qual você retornougetItemViewType
, permitindo que você crie ou configure o suporte da visualização de maneira diferente para a visualização do cabeçalho: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html# createViewHolder (android.view.ViewGroup , int)Não se esqueça de subtrair um da posição inteira passada para
bindViewHolder
.fonte
getItemViewType(int position) { return position == 0 ? 0 : 1; }
(RecyclerView
não possui umgetViewTypeCount()
método). Por outro lado, concordo com @IZI_Shadow_IZI, realmente sinto que o LayoutManager deve ser o responsável por esse tipo de coisa. Alguma outra ideia?Você pode usar esta biblioteca do GitHub , permitindo adicionar cabeçalho e / ou rodapé no seu RecyclerView da maneira mais simples possível.
Você precisa adicionar a biblioteca HFRecyclerView ao seu projeto ou também pode obtê- la em Gradle:
Este é um resultado na imagem:
EDITAR:
Se você deseja adicionar uma margem na parte superior e / ou inferior desta biblioteca: SimpleItemDecoration :
fonte
Acabei implementando meu próprio adaptador para agrupar qualquer outro adaptador e fornecer métodos para adicionar visualizações de cabeçalho e rodapé.
Criou uma essência aqui: HeaderViewRecyclerAdapter.java
A principal característica que eu queria era uma interface semelhante a um ListView, então eu queria ser capaz de inflar os pontos de vista no meu Fragmento e adicioná-los ao
RecyclerView
noonCreateView
. Isso é feito criando umaHeaderViewRecyclerAdapter
passagem do adaptador a ser empacotado e chamandoaddHeaderView
eaddFooterView
passando suas visualizações infladas. Em seguida, defina aHeaderViewRecyclerAdapter
instância como o adaptador noRecyclerView
.Um requisito extra era que eu precisava poder trocar facilmente adaptadores enquanto mantinha os cabeçalhos e rodapés. Eu não queria ter vários adaptadores com várias instâncias desses cabeçalhos e rodapés. Assim, você pode ligar
setAdapter
para alterar o adaptador acondicionado, deixando os cabeçalhos e rodapés intactos,RecyclerView
sendo notificado da alteração.fonte
minha maneira "mantenha as coisas simples e estúpidas" ... desperdice alguns recursos, eu sei, mas não me importo, pois meu código é simples, então ... 1) adicione rodapé com visibilidade GONE ao seu item_layout
2) depois configure-o no último item
faça o oposto do cabeçalho
fonte
Com base na solução da @ seb, criei uma subclasse de RecyclerView.Adapter que suporta um número arbitrário de cabeçalhos e rodapés.
https://gist.github.com/mheras/0908873267def75dc746
Embora pareça ser uma solução, também acho que isso deve ser gerenciado pelo LayoutManager. Infelizmente, eu preciso dele agora e não tenho tempo para implementar um StaggeredGridLayoutManager do zero (nem mesmo estender a partir dele).
Ainda estou testando, mas você pode experimentá-lo, se quiser. Entre em contato se encontrar algum problema.
fonte
Você pode usar o viewtype para resolver esse problema. Aqui está minha demonstração: https://github.com/yefengfreedom/RecyclerViewWithHeaderFooterLoadingEmptyViewErrorView
você pode definir o modo de exibição da exibição do reciclador:
final estático público int MODE_DATA = 0, MODE_LOADING = 1, MODE_ERROR = 2, MODE_EMPTY = 3, MODE_HEADER_VIEW = 4, MODE_FOOTER_VIEW = 5;
2. substituir o método getItemViewType
3. substitua o método getItemCount
4. substitua o método onCreateViewHolder. criar titular da vista por viewType
5. Substitua o método onBindViewHolder. vincular dados por viewType
fonte
Você pode usar a biblioteca SectionedRecyclerViewAdapter para agrupar seus itens em seções e adicionar um cabeçalho a cada seção, como na imagem abaixo:
Primeiro você cria sua classe de seção:
Em seguida, você configura o RecyclerView com suas seções e altera o SpanSize dos cabeçalhos com um GridLayoutManager:
fonte
Sei que cheguei atrasado, mas apenas recentemente consegui implementar esse "addHeader" no adaptador. No meu projeto FlexibleAdapter , você pode chamar
setHeader
um item seccionável e depois chamarshowAllHeaders
. Se você precisar de apenas 1 cabeçalho, o primeiro item deverá ter o cabeçalho. Se você excluir este item, o cabeçalho será automaticamente vinculado ao próximo.Infelizmente, os rodapés ainda não estão cobertos.
O FlexibleAdapter permite fazer muito mais do que criar cabeçalhos / seções. Você realmente deve dar uma olhada: https://github.com/davideas/FlexibleAdapter .
fonte
Gostaria apenas de adicionar uma alternativa a todas as implementações do HeaderRecyclerViewAdapter. CompoundAdapter:
https://github.com/negusoft/CompoundAdapter-android
É uma abordagem mais flexível, pois você pode criar um AdapterGroup a partir de adaptadores. Para o exemplo do cabeçalho, use seu adaptador como está, juntamente com um adaptador que contém um item para o cabeçalho:
É bastante simples e legível. Você pode implementar facilmente um adaptador mais complexo usando o mesmo princípio.
fonte