Quero corrigir minhas visualizações de cabeçalho na parte superior da tela, como na imagem abaixo e sem usar bibliotecas externas.
No meu caso, não quero fazer isso alfabeticamente. Eu tenho dois tipos diferentes de visualizações (cabeçalho e normal). Eu só quero consertar o topo, o último cabeçalho.
android
header
android-recyclerview
sticky
Jaume Colom
fonte
fonte
Respostas:
Aqui vou explicar como fazê-lo sem uma biblioteca externa. Será um post muito longo, então prepare-se.
Antes de tudo, permita-me reconhecer @ tim.paetz cuja postagem me inspirou a iniciar uma jornada de implementação de meus próprios cabeçalhos persistentes usando
ItemDecoration
s. Peguei emprestado algumas partes do código dele na minha implementação.Como você já deve ter experimentado, se você tentou fazer isso sozinho, é muito difícil encontrar uma boa explicação de COMO realmente fazer isso com a
ItemDecoration
técnica. Quero dizer, quais são os passos? Qual é a lógica por trás disso? Como coloco o cabeçalho no topo da lista? Não saber as respostas para essas perguntas é o que leva os outros a usar bibliotecas externas, enquanto faz isso sozinho com o uso deItemDecoration
é bastante fácil.Condições iniciais
list
item de tipo diferente (não no sentido "tipos Java", mas no sentido "tipos cabeçalho / item").list
deve ser um item de cabeçalho.Aqui eu forneço o código completo para o meu
RecyclerView.ItemDecoration
chamadoHeaderItemDecoration
. Depois explico os passos dados em detalhes.Logíca de negócios
Então, como faço para ficar?
Você não Você não pode fazer com que
RecyclerView
o item de sua escolha pare e fique por cima, a menos que você seja um guru de layouts personalizados e conheça mais de 12.000 linhas de código deRecyclerView
cor. Portanto, como sempre acontece com o design da interface do usuário, se você não pode fazer algo, falsifique-o. Você apenas desenha o cabeçalho em cima de tudo usandoCanvas
. Você também deve saber quais itens o usuário pode ver no momento. Acontece que issoItemDecoration
pode lhe fornecerCanvas
informações sobre itens visíveis. Com isso, aqui estão as etapas básicas:No
onDrawOver
método deRecyclerView.ItemDecoration
obter o primeiro item (superior) visível para o usuário.Determine qual cabeçalho o representa.
Desenhe o cabeçalho apropriado na parte superior do RecyclerView usando o
drawHeader()
métodoTambém quero implementar o comportamento quando o novo cabeçalho próximo encontrar o superior: deve parecer que o cabeçalho próximo empurra suavemente o cabeçalho atual superior para fora da visualização e, eventualmente, substitui-o.
A mesma técnica de "desenhar em cima de tudo" se aplica aqui.
Determine quando o cabeçalho superior "preso" encontra o novo próximo.
Obtenha esse ponto de contato (que é a parte inferior do cabeçalho pegajoso que você desenhou e a parte superior do próximo cabeçalho).
Se o item da lista estiver ultrapassando esse "ponto de contato", redesenhe o cabeçalho adesivo para que sua parte inferior fique na parte superior do item invasor. Você consegue isso com o
translate()
método daCanvas
. Como resultado, o ponto de partida do cabeçalho superior ficará fora da área visível e parecerá "sendo empurrado pelo próximo cabeçalho". Quando acabar, desenhe o novo cabeçalho no topo.O restante é explicado por comentários e anotações completas no trecho de código que forneci.
O uso é direto:
Você
mAdapter
deve implementarStickyHeaderInterface
para que ele funcione. A implementação depende dos dados que você possui.Finalmente, aqui eu forneço um gif com cabeçalhos semitransparentes, para que você possa entender a idéia e realmente ver o que está acontecendo sob o capô.
Aqui está a ilustração do conceito "basta desenhar em cima de tudo". Você pode ver que existem dois itens "cabeçalho 1" - um que desenhamos e permanece no topo em uma posição travada, e o outro que vem do conjunto de dados e se move com todos os demais itens. O usuário não verá o funcionamento interno, porque você não terá cabeçalhos semitransparentes.
E aqui o que acontece na fase "empurrando":
Espero que tenha ajudado.
Editar
Aqui está minha implementação real do
getHeaderPositionForItem()
método no adaptador do RecyclerView:Implementação ligeiramente diferente no Kotlin
fonte
private View getHeaderViewForItem(int itemPosition, RecyclerView parent) { int headerPosition = mListener.getHeaderPositionForItem(itemPosition); if(headerPosition != mCurrentHeaderIndex) { mCurrentHeader = mListener.createHeaderView(headerPosition, parent); mCurrentHeaderIndex = headerPosition; } return mCurrentHeader; }
A maneira mais fácil é criar apenas uma decoração de itens para o seu RecyclerView.
}
XML para seu cabeçalho em recycler_section_header.xml:
E, finalmente, para adicionar o item Decoration ao seu RecyclerView:
Com essa decoração de itens, você pode tornar o cabeçalho fixado / pegajoso ou não com apenas um booleano ao criar a decoração de itens.
Você pode encontrar um exemplo de trabalho completo no github: https://github.com/paetztm/recycler_view_headers
fonte
wrap_content
), você desejaria executarfixLayoutSize
depois de definir o texto do título também.Eu fiz minha própria variação da solução de Sevastyan acima
... e aqui está a implementação do StickyHeaderInterface (eu fiz isso diretamente no adaptador da recicladora):
Portanto, nesse caso, o cabeçalho não é apenas desenhar na tela, mas visualizar com seletor ou ondulação, listener de cliques etc.
fonte
recyclerView.addItemDecoration(HeaderItemDecoration(recyclerView, adapter))
. Desculpe, não consigo encontrar um exemplo de implementação que eu usei. Eu editei a resposta - adicionei algum texto aos comentáriospara quem procura uma solução para o problema de cintilação / piscada quando você já tem
DividerItemDecoration
. eu pareço ter resolvido assim:isso parece estar funcionando, mas alguém pode confirmar que eu não quebrei mais nada?
fonte
Você pode verificar e executar a implementação da classe
StickyHeaderHelper
no meu projeto FlexibleAdapter e adaptá-la ao seu caso de uso.Porém, sugiro usar a biblioteca, pois ela simplifica e reorganiza a maneira como você geralmente implementa os Adaptadores para o RecyclerView: Não reinvente a roda.
Eu diria também, não use Decoradores ou bibliotecas obsoletas, nem use bibliotecas que fazem apenas 1 ou 3 coisas; você precisará mesclar implementações de outras bibliotecas por conta própria.
fonte
Decorator
s?Outra solução, com base no ouvinte de rolagem. As condições iniciais são as mesmas da resposta de Sevastyan
Layout para ViewHolder e cabeçalho aderente.
item_header.xml
Layout para o RecyclerView
Classe para HeaderItem.
É tudo útil. A implementação do adaptador, ViewHolder e outras coisas, não é interessante para nós.
Interface para a visualização do cabeçalho de ligação.
fonte
for (int i = position; position >= 0; i--){ //should be i >= 0
Ei,
É assim que se faz, se você deseja apenas um tipo de suporte quando ele começa a sair da tela (não estamos preocupados com nenhuma seção). Só existe uma maneira de quebrar a lógica interna do RecyclerView de itens de reciclagem e aumentar a exibição adicional sobre o item de cabeçalho do recyclerView e passar dados para ele. Vou deixar o código falar.
E então você apenas faz isso no seu adaptador:
Onde YOUR_STICKY_VIEW_HOLDER_TYPE é viewType do seu suposto suporte pegajoso.
fonte
Para aqueles que podem se preocupar. Com base na resposta de Sevastyan, você deve fazer a rolagem horizontal. Simplesmente mude tudo
getBottom()
paragetRight()
egetTop()
paragetLeft()
fonte
A resposta já está aqui. Se você não quiser usar nenhuma biblioteca, siga estas etapas:
Explicação:
No
onCreateViewHolder
método, podemos verificarviewType
e, dependendo do valor (nosso tipo "especial"), inflar um layout especial.Por exemplo:
onde
class ItemElement
eclass TitleElement
pode parecer comumViewHolder
:Portanto, a ideia de tudo isso é interessante. Mas estou interessado se for efetivamente, porque precisamos classificar a lista de dados. E acho que isso diminuirá a velocidade. Se alguma idéia sobre isso, por favor escreva-me :)
E também a pergunta em aberto: é como manter o layout "especial" na parte superior, enquanto os itens estão em reciclagem. Talvez combine tudo isso com
CoordinatorLayout
.fonte