Eu estava explorando RecyclerView
e fiquei surpreso ao ver que RecyclerView
não tem onItemClickListener()
.
Eu tenho duas perguntas.
Pergunta principal
Quero saber por que o Google foi removido onItemClickListener()
?
Existe um problema de desempenho ou algo mais?
Pergunta Secundária
Resolvi meu problema escrevendo onClick
no meu RecyclerView.Adapter
:
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
@Override
public void onClick(View v) {
}
}
Isso está bem / existe alguma maneira melhor?
java
android
android-recyclerview
Tarun Varshney
fonte
fonte
QUESTION
Respostas:
tl; dr 2016 Use RxJava e um PublishSubject para expor um Observable para os cliques.
Mensagem original:
Desde a introdução de
ListView
,onItemClickListener
tem sido problemático. No momento em que você tiver um ouvinte de clique para qualquer um dos elementos internos, o retorno de chamada não será acionado, mas não foi notificado ou bem documentado (se houver), portanto houve muita confusão e perguntas SO sobre ele.Dado que
RecyclerView
isso dá um passo adiante e não tem o conceito de uma linha / coluna, mas de um número arbitrário de filhos, eles delegaram o onClick a cada um deles ou à implementação do programador.Pense
Recyclerview
não como umaListView
substituição 1: 1, mas como um componente mais flexível para casos de uso complexos. E, como você diz, sua solução é o que o Google esperava de você. Agora você tem um adaptador que pode delegar onClick para uma interface repassado o construtor, que é o padrão correto para ambosListView
eRecyclerview
.e depois no seu adaptador
Agora observe o último trecho de código:
onCreateViewHolder(ViewGroup parent, int viewType)
a assinatura já sugere diferentes tipos de exibição. Para cada um deles, você também precisará de um visualizador diferente e, posteriormente, cada um deles poderá ter um conjunto diferente de cliques. Ou você pode simplesmente criar um visualizador genérico que adote qualquer visualizaçãoonClickListener
e aplique de acordo. Ou delegar um nível ao orquestrador para que vários fragmentos / atividades tenham a mesma lista com um comportamento de clique diferente. Mais uma vez, toda a flexibilidade está do seu lado.É um componente realmente necessário e bastante próximo do que
ListView
eram nossas implementações e melhorias internas até agora. É bom que o Google finalmente o reconheça.fonte
onBindViewHolder(holder, position)
, que é onde a informação deve ser preenchida.getPosition()
está obsoleto "Este método está obsoleto porque seu significado é ambíguo devido ao tratamento assíncrono * das atualizações do adaptador. Use {@link #getLayoutPosition ()} ou * {@link #getAdapterPosition ()}, dependendo do seu caso de uso. "viewHolder.getPosition();
Por que o RecyclerView não possui
onItemClickListener
O
RecyclerView
é uma caixa de ferramentas, em contraste com o antigoListView
, possui menos recursos de criação e mais flexibilidade. EsseonItemClickListener
não é o único recurso que está sendo removido do ListView. Mas tem muitos ouvintes e método para estendê-lo ao seu gosto, é muito mais poderoso nas mãos certas;).Na minha opinião, o recurso mais complexo removido
RecyclerView
é o Fast Scroll . A maioria dos outros recursos pode ser facilmente reimplementada.Se você quiser saber quais outros recursos interessantes foram
RecyclerView
adicionados, leia esta resposta para outra pergunta.Memória eficiente - solução drop-in para onItemClickListener
Esta solução foi proposta por Hugo Visser , um Android GDE, logo após o
RecyclerView
lançamento. Ele disponibilizou uma aula sem licença para você simplesmente inserir seu código e usá-lo.Ele mostra um pouco da versatilidade introduzida com
RecyclerView
o uso deRecyclerView.OnChildAttachStateChangeListener
.Edit 2019 : versão kotlin por mim, java one, de Hugo Visser, mantida abaixo
Kotlin / Java
Crie um arquivo
values/ids.xml
e coloque-o nele:adicione o código abaixo à sua fonte
Kotlin
Uso:
(também oferece suporte a um longo clique no item e veja abaixo outro recurso que eu adicionei).
implementação (minha adaptação ao código Java Hugo Visser):
(veja abaixo você também precisa adicionar um arquivo XML)
Recurso de bônus da versão Kotlin
Às vezes, você não deseja que todos os itens do RecyclerView sejam clicáveis.
Para lidar com isso, apresentei a
ItemClickSupportViewHolder
interface que você pode usarViewHolder
para controlar qual item é clicável.Exemplo:
Java
Uso:
(também suporta clique longo no item)
Implementação (comentários adicionados por mim):
Como funciona (por que é eficiente)
Essa classe funciona anexando
RecyclerView.OnChildAttachStateChangeListener
a aoRecyclerView
. Esse ouvinte é notificado toda vez que um filho é anexado ou desanexado doRecyclerView
. O código usa isso para anexar um ouvinte de toque / clique longo à exibição. Esse ouvinte pedeRecyclerView
oRecyclerView.ViewHolder
que contém a posição.Isso é mais eficiente do que outras soluções, porque evita a criação de vários ouvintes para cada exibição e continua destruindo e criando-os enquanto a
RecyclerView
rolagem está rolando.Você também pode adaptar o código para devolver o suporte, se precisar de mais.
Observação final
Lembre-se de que é completamente bom manipulá-lo no seu adaptador, definindo em cada exibição da sua lista um ouvinte de clique, como outra resposta proposta.
Não é apenas a coisa mais eficiente a ser feita (você cria um novo ouvinte toda vez que reutiliza uma exibição), mas funciona e, na maioria dos casos, não é um problema.
Também é um pouco contra a separação de preocupações, porque não é realmente o trabalho do adaptador delegar eventos de clique.
fonte
addTo()
eremoveFrom()
. A instância está associada à tag recyclerview e morre com ela ou quando é removida manualmente.onCreateViewHolder
e pronto .RecyclerView
.Eu gosto desse jeito e estou usando
Dentro
Colocar
E crie essa classe onde quiser
Eu li antes que existe uma maneira melhor, mas eu gosto dessa maneira é fácil e não é complicada.
fonte
MyOnClickListener
em instância variável, porque você vai ser a criação de uma nova instância dela toda vez que com anew
palavra-chaverecyclerView
no MyOnClickListener?Android Recyclerview With
onItemClickListener
, Por que não podemos tentar isso está funcionandoListView
apenas?Fonte: Link
E defina-o como RecyclerView:
fonte
SwipeRefreshLayout
Graças a @marmor, atualizei minha resposta.
Eu acho que é uma boa solução para lidar com o onClick () no construtor da classe ViewHolder e passá-lo para a classe pai via OnItemClickListener interface .
MyAdapter.java
Uso do adaptador em outras classes:
MyFragment.java
fonte
onBindViewHolder()
é chamado muitas vezes para a mesma exibição ao rolar. Mesmo criar um singleOnClickListener
não ajudará, pois você redefiniráOnClickListener
toda vez queonBindViewHolder()
for chamado. Veja a solução @ MLProgrammer-CiM.MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() ....
pode criar um único ouvinte para todas as visualizações.Caras usam esse código em Sua atividade principal. Método muito eficiente
Aqui está sua classe de adaptador.
Depois disso, você obterá esse método de substituição em sua atividade.
fonte
> Como o RecyclerView é diferente do Listview?
Uma diferença é que existe uma
LayoutManager
classe no RecyclerView pela qual você pode gerenciar suasRecyclerView
preferências.Como na rolagem horizontal para o RecyclerView-
fonte
Seguindo a excelente solução RxJava do MLProgrammer-CiM
Consumir / Observar cliques
RxJava 2. +
Modifique o tl; dr original como:
PublishSubject#asObservable()
foi removido. Basta retornar oPublishSubject
que é umObservable
.fonte
Como juntar tudo exemplo ...
Tipos de ViewHolder
fonte
Tanto quanto eu entendo a resposta MLProgrammer-CiM , simplesmente é possível fazer isso:
fonte
Depois de ler a resposta do @ MLProgrammer-CiM , aqui está o meu código:
fonte
getAdapterPosition
pode retornar-1
para "nenhuma posição".Eu fiz dessa maneira, é muito simples:
Basta adicionar 1 linha para a posição Click RecyclerView :
Código completo para a classe ViewHolder :
Espero que isso ajude você.
fonte
getAdapterPosition
vez degetLayoutPosition
. Guarda contra-1
.Eu uso esse método para iniciar um Intent a partir do RecyclerView:
fonte
onBindViewHolder(...)
não é chamado apósnotify()
métodos. Portanto, você pode obter uma posição errada do clique em algumas situações.O RecyclerView não possui um
onItemClickListener
porque o RecyclerView é responsável pela reciclagem de visualizações (surpresa!), Portanto, é de responsabilidade da visualização que é reciclada lidar com os eventos de clique que recebe.Na verdade, isso facilita muito o uso, especialmente se você tiver itens que podem ser clicados em vários locais.
De qualquer forma, detectar cliques em um item do RecyclerView é muito fácil. Tudo o que você precisa fazer é definir uma interface (se você não estiver usando o Kotlin, nesse caso, basta passar um lambda):
Mesmo código no Kotlin:
O que você NÃO precisa fazer:
1.) você não precisa interceptar eventos de toque manualmente
2.) você não precisa mexer com ouvintes de alteração de estado anexados por crianças
3.) você não precisa do PublishSubject / PublishRelay do RxJava
Basta usar um ouvinte de clique.
fonte
Veja minha abordagem sobre isso:
Primeiro, declare uma interface como esta:
Em seguida, crie o adaptador:
E agora vamos ver como integrar isso a partir de um fragmento:
fonte
Se você deseja adicionar onClick () à exibição filho de itens, por exemplo, um botão no item, descobri que você pode fazer isso facilmente em onCreateViewHolder () de seu próprio RecyclerView.Adapter, assim:
não sei se é um bom caminho, mas funciona bem. Se alguém tiver uma idéia melhor, muito prazer em me dizer e corrigir minha resposta! :)
fonte
Aqui está uma maneira de implementá-lo facilmente, se você tiver uma lista de POJOs e quiser recuperar um clique de fora do adaptador.
No seu adaptador, crie um ouvinte para os eventos de clique e um método para configurá-lo:
}
No seu ViewHolder, implemente onClickListener e crie um membro da classe para armazenar temporariamente o POJO que a exibição está apresentando, dessa maneira (este é um exemplo, criar um setter seria melhor):
De volta ao seu adaptador, configure o POJO atual quando o ViewHolder estiver vinculado (ou nulo se a visualização atual não tiver uma):
É isso, agora você pode usá-lo assim em seu fragmento / atividade:
fonte
mMyAdapter.setOnItemClickListener(MyAdapter.OnItemClickListener() {});
sim você pode
fonte
Aqui você pode lidar com vários onclick, veja o código abaixo e é muito eficiente
fonte
itemView
.Modificado meu comentário ...
fonte
getAdapterPosition()
.Confira este em que eu implementei todas as coisas de maneira adequada
Classe RecyclerViewHolder
Adaptador
A interface
fonte
Isso funcionou para mim:
fonte
setOnClickListener(holder)
emonBindViewHolder()
. Porque onBindViewHolder (...) não é chamado após os métodos notify (). Portanto, você pode obter uma posição errada do clique em algumas situações.onCreateViewHolder
.Acesse o
mainView
derowLayout(cell)
para vocêRecyclerView
e em suaOnBindViewHolder
escrever este código:fonte
Em vez de implementar a interface View.OnClickListener dentro do view view ou criar e criar interface e implementar interface em sua atividade .. Eu usei esse código para simplificar a implementação do OnClickListener.
fonte
Suporte da vista interna
Por dentro do OnBindViewHolder ()
E deixe-me saber, você tem alguma dúvida sobre esta solução?
fonte
onCreateViewHolder
para obter um melhor desempenho, mas precisará obter a posição usandogetAdapterPosition()
(e se protegendo contra-1
)fonte
use PlaceHolderView
fonte
Eu escrevi uma biblioteca para lidar com o evento de clique no item de exibição do reciclador Android. Você pode encontrar todo o tutorial em https://github.com/ChathuraHettiarachchi/RecycleClick
ou para lidar com o item pressione e segure, você pode usar
fonte
A animação da reciclagem não foi testada, a outra é normal. Eu acho que foi otimizado ao máximo. Interface tem outros usos, você pode ignorar temporariamente.
Esta é a interface
Esta é uma classe abstrata
Você só precisa disso
fonte
Exemplo com getTag () / setTag () e ouvinte de clique único para o adaptador inteiro:
O TAG_POSITION definido no arquivo tags.xml como
fonte