RecyclerView onClick

583

Alguém usando RecyclerViewencontrou uma maneira de definir um onClickListenerpara itens no RecyclerView? Pensei em definir um ouvinte para cada um dos layouts de cada item, mas isso parece um pouco complicado demais. Tenho certeza de que existe uma maneira de RecyclerViewouvir o onClickevento, mas não consigo entender direito.

CurtJRees
fonte
4
RecyclerViewDemo Achei esse projeto ótimo, usando interfaces para fornecer mais ações gratuitas.
MewX
2
verificar este tutorial wiki.workassis.com/android-recyclerview-example
Bikesh M
Simples e fácil de usar - github.com/rahulkapoor1/ClickableAdapter
Rahul
stackoverflow.com/a/31199564/5788247
Shomu 13/10

Respostas:

477

Como as APIs mudaram radicalmente, não me surpreenderia se você criasse um OnClickListenerpara cada item. Não é tão complicado assim. Na sua implementação de RecyclerView.Adapter<MyViewHolder>, você deve ter:

private final OnClickListener mOnClickListener = new MyOnClickListener();

@Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.myview, parent, false);
    view.setOnClickListener(mOnClickListener);
    return new MyViewHolder(view);
}

O onClickmétodo:

@Override
public void onClick(final View view) {
    int itemPosition = mRecyclerView.getChildLayoutPosition(view);
    String item = mList.get(itemPosition);
    Toast.makeText(mContext, item, Toast.LENGTH_LONG).show();
}
nhaarman
fonte
32
e se eu quiser excluir uma linha ao clicar?
Piyush Kukadiya
20
Gosto mais desta resposta do que a que você vinculou. Quem quer escrever um ouvinte de gestos e bater na detecção de caixa para lidar com isso. Google--
Lo-Tan
17
getChildPosition (vista) é Método Reprovado
Jigar
45
Você se importa em dizer em quais classes seus trechos estão? onClick(), pertencente a, OnClickListenerpode ser anexado a QUALQUER visualização. A questão toda aqui é qual! Faça um esforço, um método não é apenas identificado por um nome, mas também pelo menos por uma classe. Se você não diz que seu código deve ser adicionado ao adaptador, sua resposta realmente não ajuda.
Vince
16
O método onClick deve estar no fragmento que contém o RecyclerView? Porque você faz referência ao mRecyclerView na sua classe MyOnClickListener. Onde você conseguiu a referência para esse objeto?
Ced
606

Aqui está uma maneira melhor e menos acoplada de implementar um OnClickListenerpara a RecyclerView.

Snippet de uso:

RecyclerView recyclerView = findViewById(R.id.recycler);
recyclerView.addOnItemTouchListener(
    new RecyclerItemClickListener(context, recyclerView ,new RecyclerItemClickListener.OnItemClickListener() {
      @Override public void onItemClick(View view, int position) {
        // do whatever
      }

      @Override public void onLongItemClick(View view, int position) {
        // do whatever
      }
    })
);

RecyclerItemClickListener implementação:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;


public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
  private OnItemClickListener mListener;

  public interface OnItemClickListener {
    public void onItemClick(View view, int position);

    public void onLongItemClick(View view, int position);
  }

  GestureDetector mGestureDetector;

  public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child != null && mListener != null) {
                mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
            }
        }
    });
}

  @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
    View childView = view.findChildViewUnder(e.getX(), e.getY());
    if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
      mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
      return true;
    }
    return false;
  }

  @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }

  @Override
  public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
}
Jacob Tabak
fonte
85
Isso não fornecerá nenhuma pista sobre qual botão ou exibição (dentro do item) foi clicada. Mas, para um clique geral do item, tudo bem.
Niranjan
27
O comentário da ngen está correto - se você deseja anexar um ouvinte onClick a um item específico na visualização do item, provavelmente deve fazer isso no seu adaptador, no onBindViewHolder ou no seu próprio visualizador.
precisa
16
Um problema com esse método é quando você está fazendo algo que leva algumas centenas de milissegundos, como iniciar uma atividade. Quando o item é clicado e ele possui uma animação clicada, há um atraso perceptível entre clicar e ver a animação.
Gak2
20
Esta solução se sente extremamente desajeitado, há algum atraso ao processar o 'click' ea sensação não é apenas ok
Wasyl
6
Alguém poderia me explicar por que essa solução com o GestureDetector deveria ser uma solução melhor do que apenas usar "setOnClickListener" dentro de onBindViewHolder () no adaptador para o elemento correspondente? Dessa forma, pelo menos eu preciso de menos código do que com a solução GestureDetector. Obrigado por uma explicação.
e-natureza
115

Faço-o desta maneira, sem classes, detectores indevidos, etc. Código simples dentro do nosso adaptador. Solução especialmente melhor por longClick do que a apresentada anteriormente.

public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> {
    private static ClickListener clickListener;

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
        TextView name;

        public ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            itemView.setOnLongClickListener(this);
            name = (TextView) itemView.findViewById(R.id.card_name);
        }

        @Override
        public void onClick(View v) {
            clickListener.onItemClick(getAdapterPosition(), v);
        }

        @Override
        public boolean onLongClick(View v) {
            clickListener.onItemLongClick(getAdapterPosition(), v);
            return false;
        }
    }

    public void setOnItemClickListener(ClickListener clickListener) {
        PasswordAdapter.clickListener = clickListener;
    }

    public interface ClickListener {
        void onItemClick(int position, View v);
        void onItemLongClick(int position, View v);
    }
}

Em seguida, dentro do fragmento ou atividade, basta pressionar:

PasswordAdapter mAdapter = ...;

mAdapter.setOnItemClickListener(new PasswordAdapter.ClickListener() {
    @Override
    public void onItemClick(int position, View v) {
        Log.d(TAG, "onItemClick position: " + position);
    }

    @Override
    public void onItemLongClick(int position, View v) {
        Log.d(TAG, "onItemLongClick pos = " + position);
    }
});
Marurban
fonte
em vez de OurAdapter.clickListener, acho que Marurban significa PasswordAdapter.clickListener e, em vez de TrainingAdapter.ClickListener (), deve ser PasswordAdapter.ClickListener (). Fora isso, ótima solução Marurban! trabalhou para mim
nommer 29/08/2015
O ouvinte onItemClick também está sendo ativado com um clique longo.
precisa saber é o seguinte
10
O ViewHolder deve ser estático para o melhor desempenho. Esta não é uma boa resposta.
Gilberto Ibarra
10
O clickListener estático cria um vazamento de memória. Declare o ouvinte como não estático e vincule-o ao ViewHolder.
BladeCoder
1
@AJW A maneira mais simples é inicializar o ouvinte mais cedo e passá-lo como argumento para o construtor Adapter e, em seguida, o construtor ViewHolder.
BladeCoder 20/05/19
97

Confira uma pergunta semelhante no link do comentário do @ CommonsWare para isso , que implementa a OnClickListenerinterface no viewHolder.

Aqui está um exemplo simples do ViewHolder:

    TextView textView;//declare global with in adapter class

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

      private ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            textView = (TextView)view.findViewById(android.R.id.text1);

      }

      @Override
      public void onClick(View view) {
            Toast.makeText(view.getContext(), "position = " + getLayoutPosition(), Toast.LENGTH_SHORT).show();

         //go through each item if you have few items within recycler view
        if(getLayoutPosition()==0){
           //Do whatever you want here

        }else if(getLayoutPosition()==1){ 
           //Do whatever you want here         

        }else if(getLayoutPosition()==2){

        }else if(getLayoutPosition()==3){

        }else if(getLayoutPosition()==4){

        }else if(getLayoutPosition()==5){

        }

        //or you can use For loop if you have long list of items. Use its length or size of the list as 
        for(int i = 0; i<exampleList.size(); i++){

        }


      }
  }

O Adapterentão se parece com isso:

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view =LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);

        return new ViewHolder(view);
    }
bolot
fonte
14
Isso parece ir na direção errada. Se você precisar reutilizar uma visualização de reciclagem em outro fragmento / atividade, o adaptador / visualizador agora está definindo a lógica dos cliques em vez do que quer que os contenha. Os cliques devem realmente ser tratados direta ou indiretamente pela instância que os contém. Parece que um ouvinte sensível ao toque é a única maneira eficaz de fazer isso.
Ola.shaun.thomas
18
@ tencent Não vejo como esse é o problema. Se o próprio ViewHolder contiver todas as informações sobre quais dados são selecionados quando o elemento em si é clicado, a única responsabilidade do contêiner é a exibição de N elementos, em vez de lidar com a seleção de um i-ésimo elemento específico dos N elementos. O ListViewjá era problemático se você tivesse que criar uma lista de objetos mais complicado do que linhas apenas simples. E se você precisar manipular eventos diferentes, dependendo de onde você clica no item no ListView? Você está ferrado. Aqui, você tem cada ouvinte.
EpicPandaForce
2
Eu concordo com @EpicPandaForce neste. Também vim para votar esta resposta depois de ler a seção do livro do Commons sobre como lidar com cliques no RecyclerViews. Até agora, funcionou muito bem para mim.
precisa saber é o seguinte
1
O findViewById está sendo usado apenas na criação do detentor da exibição aqui (daí o onCreateViewHolder). O detentor da visualização destina-se a evitar encontrar a visualização toda vez que um item é vinculado ao detentor, não na criação inicial.
stuckj
2
getPosition()está obsoleto, use getAdapterPosition()ou getLayoutPosition()substitua.
K Neeraj Lal
94

Com base na resposta de Jacob Tabak (+1 para ele), consegui adicionar o ouvinte no LongClick:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
    public interface OnItemClickListener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickListener mListener;

    private GestureDetector mGestureDetector;

    public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
        mListener = listener;

        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());

                if (childView != null && mListener != null) {
                    mListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
        View childView = view.findChildViewUnder(e.getX(), e.getY());

        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
        }

        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    }
}

Então você pode usá-lo assim:

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        // ...
    }

    @Override
    public void onItemLongClick(View view, int position) {
        // ...
    }
}));
Eng.Fouad
fonte
1
Demorei um pouco para me adaptar ao meu aplicativo e alinhar e formatar o código aos padrões Java / Android, mas, eventualmente, funcionou bem.
Milosmns 14/05
Como você adiciona uma animação para o clique longo?
Jon
1
@ Efeito clique Eng.Fouad não está funcionando usando este, embora se nós set clique ouvinte em vigor adaptador clique funciona qualquer solução para este
ingsaurabh
4
Você também deve substituirpublic void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
Paolo Rotolo
Por algum motivo, ele não retorna uma exibição clicada. No meu caso, clico em uma caixa de seleção, mas a visualização é diferente. A verificação maneira que eu:view.getId() == R.id.selection
dVaffection
63

Isto é o que funcionou para mim. Anexe o OnClickListenerao onBindView. Realmente não sei se isso afetará o desempenho, mas parece funcionar bem com pouco código.

public void onBindViewHolder(ViewHolder holder, final int position) {
    holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "Recycle Click" + position, Toast.LENGTH_SHORT).show();
            }
    });
}
Bubunyo Nyavor
fonte
5
no meu caso holder.itemView.setOnClickListener (..)
D4rWiNS
18
ele é chamado 'itemView' em vez de 'view' no meu caso, apenas dizendo para os novatos, alguns deles não entendo o que eles estão copiando, e não consegue descobrir por que não funciona
D4rWiNS
3
É a posição do layout
Bubunyo Nyavor 16/09/2015
1
para mim isso parece se aplicar somente para o último item visível e não o item clicado
Nasz Njoka Sr.
2
Essa solução parece a melhor para mim, mas como isso difere da resposta da @bolot em termos de desempenho? Ele implementou o View.OnClickListener diretamente na classe ViewHolder, que cospe o método onClick separadamente. Qual seria a melhor solução?
Edmond Tamas
46

Foi tão difícil para mim ter no ouvinte de clique do item na atividade e também ter ouvinte de clique para exibição única do item que não será acionado no ouvinte de clique do item. Depois de brincar com a resposta de Jacob Tabak, eu respeito a resposta dele no clique do item, se nenhuma outra ação de toque dentro do item for apresentada.

Eu tenho uma OnClickListenerinterface personalizada que possui um evento de clique no item que mantém a exibição do item clicado e a posição do item no adaptador. Apresento uma instância dela no construtor (ou pode ser com setter) e a anexo ao ouvinte de clique em contêiner do detentor da visualização.

Também tenho outro ouvinte de clique no adaptador (pode estar no suporte da exibição) que manipulará o clique atual da exibição no contêiner.

 public class MyRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> {

private ArrayList<String> mData;
private OnItemClickListener mOnItemClickListener;

public interface OnItemClickListener {
    public void onItemClick(View view, int position);
}

public MyRecyclerAdapter(ArrayList<String> itemsData,
        OnItemClickListener onItemClickListener) {
    mOnItemClickListener = onItemClickListener;
    this.mData = itemsData;
}

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
        int viewType) {

    View layoutView = LayoutInflater.from(mContext).inflate(
            R.layout.list_item, parent, false);

    final MyViewHolder viewHolder = new MyViewHolder(layoutView);

    viewHolder.container.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            mOnItemClickListener.onItemClick(v, viewHolder.getAdapterPosition());
        }
    });

    viewHоlder.button.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            //do button click work here with
            // mData.get( viewHolder.getAdapterPosition() );
        }
    });

    return viewHolder;
}

@Override
public int getItemCount() {
    return mData.size();
}}

Na atividade, você precisa inicializar o adaptador passando a instância do OnItemClickListener

public class FeedActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ...

    RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);

    .....

    MyRecyclerAdapter adapter = new MyRecyclerAdapter(new ArrayList<String>(), new OnItemClickListener() {

        @Override
        public void onItemClick(View view, int position) {

            ///list item was clicked
        }
    });

    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setAdapter(mFeedsAdapter);
}

E meu ViewHolder

public class MyViewHolder extends RecyclerView.ViewHolder {

public Button button;
public View container;

public MyViewHolder(View itemLayoutView) {
    super(itemLayoutView);

    container = itemLayoutView;
    button = (Button) itemLayoutView.findViewById(R.id.button);
}}
Sir NIkolay Cesar O Primeiro
fonte
Esta abordagem funcionou bem para mim - isso significa que você pode lidar com cliques na atividade, em vez de dentro da exibição de grade
leafcutter
3
Onde posso te dar dinheiro. 4 horas de pesquisa e depois li sua postagem. Obrigado pelo tempo que você levou para postar isso.
Brandon
3
Isso parece estúpido, mas isso tem alguma memória ou eficiência como um problema? Como atribuímos o ouvinte de cliques toda vez que uma visualização é desenhada, certo?
Rgv
1
@Raghav sim, toda vez que a visualização é vinculada, um novo ouvinte de clique é atribuído, mas esse é o fluxo padrão. Mas o mOnItemClickListener é criado apenas uma vez para o adaptador, apenas a visualização e sua posição são diferentes a cada clique do item;)
Sir NIkolay Cesar The First
3
Ótimo exemplo para reduzir o desempenho do aplicativo e criar uso excessivo de memória! Neste exemplo, você só precisa rolar para criar centenas de objetos inúteis, que em um momento serão inúteis e terão que ser acessados ​​como garbige. @NoobDogg está certo. Nenhum ClickListeners não precisa ser criado no onBindView. Um ouvinte de clique deve ser criado uma vez no onCreateView (ou construtor de suporte) e existe enquanto precisamos da tela com este adaptador.
Mykola Tychyna
36

Acabei precisando disso, caso alguém ache útil:

public static class ViewHolder extends RecyclerView.ViewHolder {

    public ViewHolder(View item) {

        super(item);
        item.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("RecyclerView", "onClick:" + getAdapterPosition());
            }
        });

    }
}

Fonte: http://blog.csdn.net/jwzhangjie/article/details/36868515

Ovelha Fifer
fonte
De todas as versões que tentei, essa é a que eu comecei a trabalhar. Mas tudo bem, fazer dessa maneira? Ou existe uma maneira melhor, como as melhores práticas?
Matthias Loibl
1
Até onde eu sabia, esse era o único caminho. Verifique isso para mais detalhes! stackoverflow.com/a/24933117/1508887
Fifer Sheep
Como posso abrir um novo fragmento a partir do método onclick?
hash de
5
O getAdapterPosition () substitui o getPosition ()
Kennedy Nyaga
27

Eu tenho a solução agradável para RecyclerView's onItemClickListenerpara os itens e subitens

Etapa 1- Crie uma interface

public interface OnRecyclerViewItemClickListener
{
    /**
     * Called when any item with in recyclerview or any item with in item
     * clicked
     * 
     * @param position
     *            The position of the item
     * @param id
     *            The id of the view which is clicked with in the item or
     *            -1 if the item itself clicked
     */
    public void onRecyclerViewItemClicked(int position, int id);
}

Etapa 2- Em seguida, use-o no onBindViewHoldermétodo do adaptador da seguinte maneira

/**
     * Custom created method for Setting the item click listener for the items and items with in items
     * @param listener OnRecyclerViewItemClickListener 
     */
    public void setOnItemClickListener(OnRecyclerViewItemClickListener listener)
    {
        this.listener = listener;
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position)
    {

        // viewHolder.albumBg.setBackgroundResource(_itemData[position]
        // .getImageUrl());

        viewHolder.albumName.setText(arrayList.get(position).getName());
        viewHolder.artistName.setText(arrayList.get(position).getArtistName());
        String imgUrl = arrayList.get(position).getThumbImageUrl();

        makeImageRequest(imgUrl, viewHolder);
        viewHolder.parentView.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                listener.onRecyclerViewItemClicked(position, -1);
            }
        });
        viewHolder.settingButton.setOnClickListener(new View.OnClickListener()
        {

            @Override
            public void onClick(View v)
            {
                listener.onRecyclerViewItemClicked(position, v.getId());
            }
        });

    }

    // class to hold a reference to each item of RecyclerView
    public static class ViewHolder extends RecyclerView.ViewHolder
    {

        public TextView albumName, artistName;
        public ImageView albumIcon, settingButton;
        public LinearLayout parentView;

        public ViewHolder(View itemLayoutView)
        {
            super(itemLayoutView);
            // albumBg = (LinearLayout) itemLayoutView
            // .findViewById(R.id.albumDlbg);
            albumName = (TextView) itemLayoutView.findViewById(R.id.albumName);
            artistName = (TextView) itemLayoutView
                    .findViewById(R.id.artistName);
            albumIcon = (ImageView) itemLayoutView.findViewById(R.id.albumIcon);
            parentView = (LinearLayout) itemLayoutView
                    .findViewById(R.id.albumDlbg);
            settingButton = (ImageView) itemLayoutView
                    .findViewById(R.id.settingBtn);
        }

    }

Etapa 3- encontre e configure a visualização do reciclador na atividade ou fragmento em que você está usando este

recyclerView = (RecyclerView) rootview.findViewById(R.id.vmtopsongs);

        lm = new LinearLayoutManager(mActivity);
        lm.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(lm);
        recyclerView.addItemDecoration(
                new HorizontalDividerItemDecoration.Builder(getActivity())
                        .paint(Utils.getPaint()).build());
        PopularSongsadapter mAdapter = new PopularSongsadapter(gallery,
                mActivity, true);
        // set adapter
        recyclerView.setAdapter(mAdapter);
        mAdapter.setOnItemClickListener(this);
        // set item animator to DefaultAnimator
        recyclerView.setItemAnimator(new DefaultItemAnimator());

Etapa 4- Finalmente implemente a interface na atividade ou fragmento em que você está usando a visão de reciclagem

@Override
    public void onRecyclerViewItemClicked(int position, int id)
    {
        if(id==-1){
            Toast.makeText(mActivity, "complete item clicked", Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(mActivity, "setting button clicked", Toast.LENGTH_LONG).show();
        }
    }
Gopal Singh Sirvi
fonte
2
Esta é a melhor solução, porque geralmente precisamos de muitas propriedades de atividade / fragmento em nosso onItemClickListener, e não faz sentido chamá-lo diretamente do visualizador (eu precisaria criar um construtor personalizado para cada adaptador). A propósito, seu código é um pouco extenso, sugiro que você o corte na parte mais importante (setOnItemClickListener).
sagits
esta é uma boa abordagem simples para diferenciar a linha / item do sub-itens
Nigel Savage
17

Aqui está o que eu fiz. Esta solução suporta onClick e onLongClick nos itens e visualizações do RecyclerView, dentro dos itens do RecyclerView (visualizações internas).

Eu codifico viewHolder nas visualizações de minha escolha:

public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, null);
    ViewHolder viewHolder = new ViewHolder(itemView);

    itemView.setOnClickListener( this);
    itemView.setOnLongClickListener(this);
    viewHolder.imageIV.setOnClickListener(this);
    viewHolder.imageIV.setOnLongClickListener(this);

    viewHolder.imageIV.setTag(viewHolder);
    itemView.setTag(viewHolder);

    return viewHolder;
}

E eu uso holder.getPosition () para recuperar a posição no método onClick () (onLongClick é semelhante):

public void onClick(View view) {
    ViewHolder holder = (ViewHolder) view.getTag();
    int position = holder.getPosition();

    if (view.getId() == holder.imageIV.getId()){
        Toast.makeText(context, "imageIV onClick at" + position, Toast.LENGTH_SHORT).show();
    } else {
        Toast.makeText(context, "RecyclerView Item onClick at " + position, Toast.LENGTH_SHORT).show();
    }
}

Uma variante com getChildPosition também funciona. Observe que, para as visualizações internas, em onClick () use:

int position = recyclerView.getChildPosition((View)view.getParent());

Na minha opinião, a vantagem dessa solução é que, quando alguém clica na imagem, apenas o ouvinte da imagem onclick () é chamado, enquanto que quando eu combinei a solução de Jacob para uma visualização do Item RecyclerView e minha solução para visualizações internas na visualização do item RecyclerView onclick ( ) também é chamado (quando clicar na imagem).

u2gilles
fonte
11

Existe uma maneira muito mais fácil de fazer isso. Basta aplicar ao clicar na onBindViewHoldervisualização raiz.

Considere que esta é sua visão para o adaptador,

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

        <TextView
            android:id="@+id/textview"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="1dp"
            android:textSize="15sp" />
</LinearLayout>

Em seguida, faça o seguinte no seu adaptador

//get the layout and make view holder
@Override
public RVAdapter.ViewHolder1 onCreateViewHolder(ViewGroup parent, int viewType) {

    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout, null);
    ViewHolder1 viewHolder = new ViewHolder1(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(RVAdapter.ViewHolder1 holder, int position) {

    //apply on click on your root view
    holder.linearlayout.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //Do on click stuff
        }
    });
}

//make references to views in layout including root view
public class ViewHolder1 extends RecyclerView.ViewHolder {

    protected LinearLayout linearlayout = null
    protected TextView textview = null;

    public CareerLinksViewHolder(View itemView) {
        super(itemView);

        this.linearlayout = (LinearLayout) itemView.findViewById(R.id.linearlayout);
        this.tvCompName = (TextView) itemView.findViewById(R.id.textview);
    }
}
Sushant
fonte
9

Você pode passar um clickListenerpara Adapter.

No seu Activity:

private View.OnClickListener mItemClick = new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        Intent intent = null;
        int position = list.getChildPosition(v);
        switch (position) {
            case 0:
                intent = new Intent(MainActivity.this, LeakCanaryActivity.class);
                break;
            case 1:
                intent = new Intent(MainActivity.this, ButterKnifeFragmentActivity.class);
                break;
        }
        if (intent != null) {
            MainActivity.this.startActivity(intent);
        }
    }
};

depois passe para Adapter:

MainAdapter mainAdapter = new MainAdapter(this, mItemClick);

In Adapter's onCreateViewHolder:

 @Override
public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
    View itemView = activity.getLayoutInflater().inflate(R.layout.main_adapter_item, viewGroup, false);
    ViewHolder holder = new ViewHolder(itemView);
    itemView.setOnClickListener(mItemClick);
    return holder;
}
Francis Shi
fonte
Como você passa os holdervalores através da intenção?
RoCk RoCk
8

Eu desenvolvi uma biblioteca leve para android, você pode visitar https://github.com/ChathuraHettiarachchi/RecycleClick

e siga para a amostra a seguir

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
            }
        });
Chathura Jayanath
fonte
Pode confirmar, esta biblioteca é ótima! Muito fácil de usar, bom trabalho!
Peterkodermac
7

Você pode implementar OnClickListener na sua classe ViewHolder

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public Item item
        @InjectView(R.id.tv_title)
        public TextView tvTitle;
        @InjectView(R.id.rl_row)
        public RelativeLayout rlRow;

        public ViewHolder(View v) {
            super(v);
            ButterKnife.inject(this, v);
            v.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            Log.e("item title",item.getTitle());
        }
    }

E onBindViewHolder define o item do seu detentor da visualização

public void onBindViewHolder(ViewHolder holder, int position) {
        holder.tvTitle.setText(objects.get(position).getTitle());
        holder.item = objects.get(position);
        }
savepopulation
fonte
7

Muito simples e eficaz.

Em vez de implementar uma interface View.OnClickListenerdentro do view view ou criar uma interface e implementar uma interface em sua atividade - usei esse código para simplificar a OnClickListenerimplementação.

public static class SimpleStringRecyclerViewAdapter
            extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {

        // Your initializations goes here...
        private List<String> mValues;

        public static class ViewHolder extends RecyclerView.ViewHolder {

            //create a variable mView
            public final View mView;

            /*All your row widgets goes here
            public final ImageView mImageView;
            public final TextView mTextView;*/

            public ViewHolder(View view) {
                super(view);
                //Initialize it here
                mView = view;

                /* your row widgets initializations goes here
                mImageView = (ImageView) view.findViewById(R.id.avatar);
                mTextView = (TextView) view.findViewById(android.R.id.text1);*/
            }
        }

        public String getValueAt(int position) {
            return mValues.get(position);
        }

        public SimpleStringRecyclerViewAdapter(Context context, List<String> items) {

            mBackground = mTypedValue.resourceId;
            mValues = items;
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.list_item, parent, false);
            view.setBackgroundResource(mBackground);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(final ViewHolder holder, int position) {
            holder.mBoundString = mValues.get(position);
            holder.mTextView.setText(mValues.get(position));

            //Here it is simply write onItemClick listener here
            holder.mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Context context = v.getContext();
                    Intent intent = new Intent(context, ExampleActivity.class);

                    context.startActivity(intent);
                }
            });
        }

        @Override
        public int getItemCount() {
            return mValues.size();
        }
    }
Manikanta
fonte
3
Essa é uma prática ruim comum porque parece muito fácil. Você está criando um novo ouvinte interno toda vez que um objeto é vinculado (e cada item em um reciclador pode ser vinculado várias vezes), o que é ruim para a) desempenho b) coleta de lixo. Em vez disso, você deve criar UM ouvinte em algum lugar (no observador, no adaptador, no fragmento ou atividade superior) e apenas adicioná-lo aos itens no construtor do observador no onCreateViewHolder. Isso tem a complexidade adicional de ter que descobrir qual item foi clicado, mas pode ser resolvido facilmente por meio de tags ou adicionando mais informações ao titular.
GuillermoMP
6

Todas as respostas postadas até o momento são ótimas soluções; no entanto, se você não deseja lidar com muitos detalhes de implementação e deseja que ele funcione de maneira semelhante à do ListView, eu recomendaria o uso do TwoWay-View, como visto aqui:

https://github.com/lucasr/twoway-view

Observe que esta implementação também suporta pressão prolongada nos itens, bem como suporte para estados pressionados (o que é algo importante que falta a outras soluções para essa pergunta).

Se você não quiser usar a biblioteca inteira, consulte a classe ClickItemTouchListener , que pode ser usada como autônoma, se necessário. O único problema que encontrei com ele no momento é com pressão prolongada + rolagem, parece ter um comportamento incorreto.

Jawnnypoo
fonte
6

Se você deseja capturar os eventos de clique em Itens individuais, basta implementar OnClickListenerna ViewHolderclasse e definir ouvintes de clique em visualizações individuais ou inteiras itemView.

O exemplo a seguir mostra o mesmo

public  class ContactViewHolder extends RecyclerView.ViewHolder implements OnClickListener
    {
        TextView txt_title,txt_name,txt_email;

        public ContactViewHolder(View itemView) 
        {
            super(itemView);
            txt_title = (TextView)itemView.findViewById(R.id.txt_title);
            txt_name  = (TextView)itemView.findViewById(R.id.txt_name);
            txt_email = (TextView)itemView.findViewById(R.id.txt_email);

            txt_name.setOnClickListener(this);
            txt_email.setOnClickListener(this);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub

            if(v == itemView)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Visiting Card Clicked is ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
            }

            if(v == txt_name)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Name ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
            }

            if(v == txt_email)
            {
                Toast.makeText(RecyclerDemoActivity.this, "Email ==>"+txt_email.getText(), Toast.LENGTH_SHORT).show();
            }
        }

    }
} 
HemangNirmal
fonte
5

Para mim, esta é a melhor maneira:

class YourRecyclerAdapter extends RecyclerView.Adapter<ContactViewHolder> implements View.OnClickListener { 
  ...
  @Override
  public void onClick(View view) {
        int itemPosition = vRecycle.getChildPosition(view);
        //And use itemPosition to get the item from your collection. This way you dont restrain the ViewHolder with a OnClick callback
    }
  ...
}
4gus71n
fonte
3
getChildPosition () é decapitada
Nasz Njoka Ir
5

O RecyclerViewnão tem um OnClickListenere terá que implementá-lo nós mesmos.

Eu gosto de adicionar uma OnItemClickListenerinterface Adaptercom um onClickmétodo chamado quando você clica na exibição do item no ViewHolder. Portanto, a responsabilidade de gerenciar o clique em um item fica fora do ViewHoldere Adapter. A atividade ou fragmento que decidirá o que fazer

Adicione uma interface ao ouvinte e ao objeto do ouvinte.

public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ViewHolder> {

  ...

  private static OnItemClickListener onItemClickListener;

  ...

  public static interface OnItemClickListener {
      public void onItemClick(View view, int position);
  }

  ...
}

Capturamos o clique da visualização raiz do item e, quando o retorno de chamada é acionado, o onClickouvinte chama o adaptador.

public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ViewHolder> {

  ...

  private static OnItemClickListener onItemClickListener;

  ...

  public static interface OnItemClickListener {
      public void onItemClick(View view, int position);
  }

  ...

  public static class ViewHolder extends RecyclerView.ViewHolder {
      public ImageView imageView;

      public ViewHolder(View itemRootView) {
          super(itemRootView);
          imageView = (ImageView) itemRootView.findViewById(R.id.itemImage);

          itemRootView.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View view) {
                  int position  = ViewHolder.super.getAdapterPosition();
                  onItemClickListener.onItemClick(view,position);
              }
          });
      }
  }
}

Como a atividade ou fragmento, fragmento no nosso caso, atribuímos um ouvinte ao adaptador e ao retorno de chamada onClick, obteremos o item selecionado por posição e abrimos uma atividade detalhada do item.

public class ItemsFragment extends Fragment {
    ...
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
       ...    
        ((ItemsAdapter) adapter).setOnItemClickListener(new ItemsAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                //Do something when an item has been clicked
            }
        });
        ...
    }
...
}
xurxodev
fonte
5

Infelizmente, RecyclerViewfaltam alguns recursos ListViewincorporados. Por exemplo, a capacidade de adicionar um OnItemClickListenerque dispara quando um item é clicado. RecyclerViewpermite que você defina um OnClickListenerno seu adaptador, mas passar o ouvinte de clique do seu código de chamada, para o adaptador e para o ViewHolder, é complicado para capturar um simples clique no item.

public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (mOnItemClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
    }
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        if (mOnItemLongClickListener != null) {
            RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
            return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
        }
        return false;
    }
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
        = new RecyclerView.OnChildAttachStateChangeListener() {
    @Override
    public void onChildViewAttachedToWindow(View view) {
        if (mOnItemClickListener != null) {
            view.setOnClickListener(mOnClickListener);
        }
        if (mOnItemLongClickListener != null) {
            view.setOnLongClickListener(mOnLongClickListener);
        }
    }

    @Override
    public void onChildViewDetachedFromWindow(View view) {

    }
};

private ItemClickSupport(RecyclerView recyclerView) {
    mRecyclerView = recyclerView;
    mRecyclerView.setTag(R.id.item_click_support, this);
    mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}

public static ItemClickSupport addTo(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support == null) {
        support = new ItemClickSupport(view);
    }
    return support;
}

public static ItemClickSupport removeFrom(RecyclerView view) {
    ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
    if (support != null) {
        support.detach(view);
    }
    return support;
}

public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
    mOnItemClickListener = listener;
    return this;
}

public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
    mOnItemLongClickListener = listener;
    return this;
}

private void detach(RecyclerView view) {
    view.removeOnChildAttachStateChangeListener(mAttachListener);
    view.setTag(R.id.item_click_support, null);
}

public interface OnItemClickListener {

    void onItemClicked(RecyclerView recyclerView, int position, View v);
}

public interface OnItemLongClickListener {

    boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}

Você também precisa definir R.id.item_click_supportusando ids.xml:

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
  <item name="item_click_support" type="id" />
 </resources>

O ouvinte de clique no código resultante agora se parece com o seguinte:

ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
    // do it
}
});

Para uma breve explicação sobre cliques na visualização de reciclagem, consulte este littlerobots_blog

anand krish
fonte
5

você pode definir facilmente setOnClickListener na sua classe ViewHolder da seguinte maneira:

public class ViewHolder extends RecyclerView.ViewHolder {
    TextView product_name;

    ViewHolder(View itemView) {
        super(itemView);
        product_name = (TextView) itemView.findViewById(R.id.product_name);
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                int itemPosition = getLayoutPosition();
                Toast.makeText(getApplicationContext(), itemPosition + ":" + String.valueOf(product_name.getText()), Toast.LENGTH_SHORT).show();
            }
        });
    }
}
Arash Hatami
fonte
5

Aqui está o que eu fiz Leia mais e faça o download da essência aqui

Adicionando o mesmo aqui

CustomItemClickListener.java

public interface CustomItemClickListener {
 public void onItemClick(View v, int position);
}

ItemsListAdapter.java

public class ItemsListAdapter extends RecyclerView.Adapter<ItemsListAdapter.ViewHolder> {
ArrayList<ItemListSingleItem> data;

Context mContext;
CustomItemClickListener listener;

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.items_list_single_item, parent, false);
    final ViewHolder mViewHolder = new ViewHolder(mView);
    mView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            listener.onItemClick(v, mViewHolder.getAdapterPosition());
        }
    });
    return mViewHolder;
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    holder.itemTitle.setText(Html.fromHtml(data.get(position).getTitle()));
    if (!TextUtils.isEmpty(data.get(position).getThumbnailURL())) {
      // I Love picasso library :) http://square.github.io/picasso/
        Picasso.with(mContext).load(data.get(position).getThumbnailURL()).error(R.drawable.ic_no_image).
                placeholder(R.drawable.ic_no_image).
                transform(new RoundedCornersTransformation(5, 0)).
                into(holder.thumbnailImage);
    } else {
        holder.thumbnailImage.setImageResource(R.drawable.ic_no_image);
    }
}


@Override
public int getItemCount() {
    return data.size();
}

public ItemsListAdapter(Context mContext, ArrayList<ItemsListSingleItem> data, CustomItemClickListener listener) {
    this.data = data;
    this.mContext = mContext;
    this.listener = listener;
}

public static class ViewHolder extends RecyclerView.ViewHolder {
    public TextView itemTitle;
    public ImageView thumbnailImage;

    ViewHolder(View v) {
        super(v);
        itemTitle = (TextView) v
                .findViewById(R.id.post_title);
        thumbnailImage = (ImageView) v.findViewById(R.id.post_thumb_image);
    }
 }
}
Muhammad Riyaz
fonte
4

Da maioria das respostas acima, eles parecem estar definindo seus ouvintes de um clique para itens individuais. No entanto, a solução que estou prestes a oferecer é muito simples, mas ainda não é intuitiva para muitos. Muitos estão esquecendo que os outros componentes estão sempre em um componente pai, usado para exibir itens nas visualizações Lista ou Reciclador. Essa solução consiste em definir um único ouvinte de onclick para essa visualização principal e a vez é executada. A solução também inclui uma maneira de passar a posição do item que está sendo clicado na exibição em lista ou recicladora. Aqui, nosso rootview principal é um CardView da biblioteca de suporte do Android. Aqui está o código de exemplo

public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {

public static final String LOG_TAG = ListAdapter.class.getSimpleName();
private Cursor mDataset;
private Context mContext;
private ViewHolder mViewHolder;

// Provide a suitable constructor (depends on the kind of dataset)
public ListAdapter(Context context, Cursor Dataset) {
    mDataset = Dataset;
    mContext = context;
}

// Create new views (invoked by the layout manager)
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    // create a new view
    View v = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.list_business_view, parent, false);

    mViewHolder = new ViewHolder(v);
    return mViewHolder;
}

public void setData(Cursor newdata) {
    this.mDataset = newdata;
}

// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Bind data to other items here. To save time, i have ommited that.
           //here is where we attach a click listerner for an item in the recycler list rather than for each element of a given item.
            holder.card.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext, " Just cliked item at position " + itemPosition, Toast.LENGTH_LONG).show();

            }
        });

    }
}

// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
    if (null != mDataset) {
        return mDataset.getCount();
    }
    return 0;

}


// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder{
    // each data item is just a string in this case
    public final TextView mBusinesssName; // View for the business name
    public final TextView mBusinessCategory; //View for the category name
    public final ImageView businessImage; // View for the business category image Image
    public final TextView mBusinessDistance; // View for the distance
    public final CardView card;

    public ViewHolder(View view) {
        super(view);
        mBusinesssName = (TextView) view.findViewById(R.id.list_item_name_textview);
        mBusinessCategory = (TextView) view.findViewById(R.id.list_item_category_textview);
        mBusinessDistance = (TextView) view.findViewById(R.id.list_item_dist_textview);
        businessImage = (ImageView) view.findViewById(R.id.list_item_icon);
        card = (CardView) view.findViewById(R.id.card_view);

    }
}
}
larrytech
fonte
4

Implementação de Kotlin da resposta de nhaarman :

mRecyclerView.addOnItemTouchListener(object  : RecyclerItemClickListener(this, mRecyclerView,object :RecyclerItemClickListener.OnItemClickListener{
            override fun onItemClick(view: View, position: Int) {

            }

            override fun onLongItemClick(view: View?, position: Int) {

            }
}){})

RecyclerItemClickListener.java:

import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View


open class RecyclerItemClickListener(context: Context, recyclerView: RecyclerView, private val mListener: OnItemClickListener?) : RecyclerView.OnItemTouchListener {

    private var mGestureDetector: GestureDetector

    interface OnItemClickListener {
        fun onItemClick(view: View, position: Int)

        fun onLongItemClick(view: View?, position: Int)
    }

    init {
        mGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
            override fun onSingleTapUp(e: MotionEvent): Boolean {
                return true
            }

            override fun onLongPress(e: MotionEvent) {
                val child = recyclerView.findChildViewUnder(e.x, e.y)
                if (child != null && mListener != null) {
                    mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child))
                }
            }
        })
    }

    override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean {
        val childView = view.findChildViewUnder(e.x, e.y)
        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView))
            return true
        }
        return false
    }

    override fun onTouchEvent(view: RecyclerView, motionEvent: MotionEvent) {}

    override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
}
Nilesh Deokar
fonte
3
public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView title, year, genre;

        public MyViewHolder(View view) {
            super(view);
            title = (TextView) view.findViewById(R.id.title);
            genre = (TextView) view.findViewById(R.id.genre);
            year = (TextView) view.findViewById(R.id.year);
            view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, ""+getAdapterPosition(), Toast.LENGTH_SHORT).show();
                }
            });
        }
    }
Null Pointer Exception
fonte
3

aqui está o código completo para o meu adaptador personalizado, esse código aumentará as linhas com os itens da lista definidos no arquivo xml chamado "list_item"; ele também executará o evento click em todas as linhas dos itens da lista com as respectivas posições.

public class MyCustomAdapter extends RecyclerView.Adapter`<`AdapterMyCustomAdapter.ViewHolder> {

    public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
        public onItemClickListener mListener;
        public ViewHolder(View v, onItemClickListener listener) {
            super(v);
            mListener =listener;
            v.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            mListener.onRecyclerItemClick(v, getPosition());
        }

        public static interface onItemClickListener {
            public void onRecyclerItemClick(View view , int position);
        }
    }

    @Override
    public int getItemCount() {
        return 5;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int pos) {      

    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
        View v = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.list_item, parent, false);

    /* here list_item is an xml file we want to inflate ...it is same as we do in case of listview for customization.*/

        MyCustomAdapter.ViewHolder vh = new ViewHolder(v, new MyCustomAdapter.ViewHolder.onItemClickListener() {

            @Override
            public void onRecyclerItemClick(View view, int position) {
                System.out.println("clicked on list item at position " +position);
            } 
        });
        return vh;
    }
}
Lone_iqbal
fonte
2

Podemos fazer isso usando referências fracas do Java. Semanticamente, o detentor da exibição é aquele que deve responder ao evento click ou delegá-lo ao respondente correto.

Nossos objetivos:

  1. O Observador não deve saber nada sobre a classe que está respondendo aos eventos, exceto que ela implementa uma determinada interface.
  2. O manipulador de cliques deve obter a posição no RecyclerView da exibição clicada.
  3. Deveríamos ser capazes de discernir em qual vista foi clicada no respectivo titular.
  4. Mantenha o acoplamento frouxo entre todos os componentes e não cause ciclos de retenção.

Passos:

  1. Crie uma interface para lidar com respostas de clique.

  2. Implemente essa interface na Atividade que manipulará o clique.

  3. Adicione uma variável de membro no RecyclerView Adapter para armazenar a Weak Reference e um construtor que a define.

  4. Faça o mesmo no RecyclerView ViewHolder e adicione uma variável de membro para acompanhar a posição.

  5. Defina seus ouvintes com um clique em qualquer visualização que desejar no ViewHolder e, em seguida, retorne a chamada para o respondente para lidar com eles.

  6. Altere seu método onBindViewHolder para definir a posição ao vincular.

  7. Passe o atendedor para o ViewHolder.

  8. No respondedor, agora você pode usar getId () na exibição para descobrir em qual exibição foi clicada.

E aqui está um Gist para que você possa ver como tudo se encaixa: RecyclerView manipulação de cliques

Rajiev Timal
fonte
2

Estou ciente de que há muitas respostas, mas achei que também poderia fornecer minha implementação. (Detalhes completos podem ser encontrados em outra pergunta que eu respondi ).

Portanto, para adicionar um ouvinte de clique, sua ViewHolderclasse interna precisa implementar View.OnClickListener. Isso ocorre porque você definirá um OnClickListenerpara o itemViewparâmetro do ViewHolderconstrutor do. Deixe-me mostrar o que eu quero dizer:

public class ExampleClickViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView text1, text2;

    ExampleClickViewHolder(View itemView) {
        super(itemView);

        // we do this because we want to check when an item has been clicked:
        itemView.setOnClickListener(this);

        // now, like before, we assign our View variables
        title = (TextView) itemView.findViewById(R.id.text1);
        subtitle = (TextView) itemView.findViewById(R.id.text2);
    }

    @Override
    public void onClick(View v) {
        // The user may not set a click listener for list items, in which case our listener
        // will be null, so we need to check for this
        if (mOnEntryClickListener != null) {
            mOnEntryClickListener.onEntryClick(v, getLayoutPosition());
        }
    }
}

As únicas outras coisas que você precisa adicionar são uma interface personalizada para você Adaptere um método setter:

private OnEntryClickListener mOnEntryClickListener;

public interface OnEntryClickListener {
    void onEntryClick(View view, int position);
}

public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) {
    mOnEntryClickListener = onEntryClickListener;
}

Portanto, seu novo suporte a cliques Adapterestá completo.

Agora, vamos usá-lo ...

    ExampleClickAdapter clickAdapter = new ExampleClickAdapter(yourObjects);
    clickAdapter.setOnEntryClickListener(new ExampleClickAdapter.OnEntryClickListener() {
        @Override
        public void onEntryClick(View view, int position) {
            // stuff that will happen when a list item is clicked
        }
    });

É basicamente como você configuraria um normal Adapter, exceto pelo uso do método setter criado para controlar o que você fará quando o usuário clicar em um item específico da lista.

Você também pode ver um conjunto de exemplos que fiz neste Gist no GitHub:

https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07

Farbod Salamat-Zadeh
fonte
Você deve usar getAdapterPosition () em vez de getLayoutPosition ()
BladeCoder
2

Isto é o que eu faço para reutilizar OnClickListener

  public class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyviewHolder>
                                         implements View.OnClickListener

no ViewHoder Pegue o pai do itemlayout

  public class MyviewHolder extends RecyclerView.ViewHolder {

       LinearLayout linearLayout_item;

        public MyviewHolder(View itemView) {
            super(itemView);
            linearLayout_item=itemView.findViewById(R.id.linearLayout_item);
        }
    }

no onBindViewHolder definir tag como posição

   @Override
    public void onBindViewHolder(MyviewHolder holder, int position) {

       holder.linearLayout_item.setTag(position);
       holder.linearLayout_item.setOnClickListener(this);
    }

e no Onclick

 @Override
public void onClick(View v) {

    int position = (int) v.getTag();
    switch (v.getId()) {
        case R.id.linearLayout_item:

            // do some thing with position 

            break;
    }
}
Manohar Reddy
fonte
2

Para mim, a maneira limpa de fazer isso é essa.

Construtor do adaptador

private class EnvironmentTypeRecyclerViewAdapter extends RecyclerView.Adapter<EnvironmentTypeRecyclerViewAdapter.ViewHolder>
{
     private final EnvironmentTypeRecyclerViewAdapterListener mEnvironmentTypeRecyclerViewAdapterListener;
     private List<Environment> mEnvironmentsData;

     public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
     {
         public ViewHolder(View v)
         {
             super(v);
             v.setOnClickListener(this);

         }

         @Override
         public void onClick(View v)
         {
              Environment environment = mEnvironmentsData.get(getAdapterPosition());
              if (mEnvironmentTypeRecyclerViewAdapterListener != null && environment != null) {
                      mEnvironmentTypeRecyclerViewAdapterListener.onListItemSelected(environment);      
              }
        }

        public EnvironmentTypeRecyclerViewAdapter(List<SmallCellEnvironment> environments, EnvironmentTypeRecyclerViewAdapterListener environmentTypeRecyclerViewAdapterListener)
        {
            mEnvironmentTypeRecyclerViewAdapterListener = environmentTypeRecyclerViewAdapterListener;
            mEnvironmentsData = environments;
        }
}

A interface vinculada

private interface EnvironmentTypeRecyclerViewAdapterListener
{
    void onListItemSelected(Environment environment);
}
Jeremie Petitjean
fonte