RecyclerView onClick

583

Czy ktoś za pomocą RecyclerViewznalazł sposób, aby ustawić onClickListenerelementy w RecyclerView? Pomyślałem o ustawieniu detektora do każdego układu dla każdego elementu, ale wydaje mi się to zbyt wielkim kłopotem. Jestem pewien, że istnieje sposób, RecyclerViewaby nasłuchiwać tego onClickwydarzenia, ale nie jestem w stanie tego rozgryźć.

CurtJRees
źródło
4
RecyclerViewDemo Uważam, że ten projekt jest świetny, używając interfejsów, aby zapewnić więcej bezpłatnych akcji.
MewX
2
sprawdź ten samouczek wiki.workassis.com/android-recyclerview-example
Bikesh M
Prosty i łatwy w użyciu - github.com/rahulkapoor1/ClickableAdapter
Rahul
stackoverflow.com/a/31199564/5788247
Shomu,

Odpowiedzi:

477

Ponieważ interfejsy API uległy radykalnej zmianie, nie zaskoczyłoby mnie, gdybyś stworzył OnClickListenerdla każdego elementu. Nie jest to jednak żaden problem. W swojej realizacji RecyclerView.Adapter<MyViewHolder>powinieneś mieć:

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);
}

onClickMetoda:

@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
źródło
32
co jeśli chcę usunąć wiersz po kliknięciu?
Piyush Kukadiya
20
Podoba mi się ta odpowiedź bardziej niż ta, którą połączyłeś. Kto chce napisać nasłuchiwanie gestów i wykrywanie trafień, aby sobie z tym poradzić. Google--
Lo-Tan,
17
getChildPosition (widok) jest przestarzałą metodą
Jigar 15.04.15
45
Czy masz ochotę powiedzieć, w których klasach znajdują się twoje fragmenty? onClick(), należące do OnClickListenermożna dołączyć do DOWOLNEGO widoku. Całe pytanie tutaj brzmi: które! Spróbuj, metoda jest nie tylko identyfikowana przez nazwę, ale także przez klasę. Jeśli nie mówisz, że twój kod ma zostać dodany do adaptera, twoja odpowiedź tak naprawdę nie pomaga.
Vince
16
Czy metoda onClick powinna znajdować się we fragmencie zawierającym RecyclerView? Ponieważ odwołujesz się do mRecyclerView w swojej klasie MyOnClickListener. Skąd masz odniesienie do tego obiektu?
Ced
605

Oto lepszy i mniej ściśle powiązany sposób na wdrożenie OnClickListenerfor a RecyclerView.

Fragment użycia:

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 realizacja:

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
źródło
85
Nie dostarczy to żadnej wskazówki, który przycisk lub widok (w elemencie) został kliknięty. Ale w przypadku ogólnego kliknięcia elementu jest to w porządku.
Niranjan
27
komentarz ngen jest poprawny - jeśli chcesz dołączyć detektor onClick do określonego elementu w widoku elementu, prawdopodobnie powinieneś to zrobić w adapterze, w onBindViewHolder lub w samym module wyświetlającym.
Jacob Tabak,
16
Jednym z problemów związanych z tą metodą jest wykonywanie czegoś, co zajmuje kilkaset milisekund, np. Rozpoczęcie działania. Gdy element zostanie kliknięty i ma klikniętą animację, zauważalne jest opóźnienie między kliknięciem a obejrzeniem animacji.
Gak2,
20
To rozwiązanie jest wyjątkowo niezgrabne, przetwarzanie „kliknięcia” jest trochę opóźnione, a odczucie nie jest po prostu w porządku
wasyl
6
Czy ktoś mógłby mi wyjaśnić, dlaczego to rozwiązanie z GestureDetector ma być lepszym rozwiązaniem niż użycie „setOnClickListener” wewnątrz onBindViewHolder () w adapterze do odpowiedniego elementu? W ten sposób potrzebuję przynajmniej mniej kodu niż w przypadku rozwiązania GestureDetector. Dziękuję za wyjaśnienie.
e-natura,
115

Robię to w ten sposób, bez zbędnych klas, detektorów itp. Prosty kod wewnątrz naszego adaptera. Szczególnie lepsze rozwiązanie dla longClick niż przedstawione wcześniej.

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);
    }
}

Następnie wewnątrz fragmentu lub aktywności, po prostu naciśnij:

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
źródło
zamiast OurAdapter.clickListener myślę, że Marurban oznacza PasswordAdapter.clickListener, a zamiast TrainingAdapter.ClickListener (), powinno być PasswordAdapter.ClickListener (). Poza tym świetne rozwiązanie Marurban! pracował dla mnie
zwykle
Odbiornik onItemClick jest również aktywowany przy długim kliknięciu.
Rashad.Z
10
ViewHolder musi być statyczny, aby uzyskać najlepszą wydajność. to nie jest dobra odpowiedź.
Gilberto Ibarra
10
Statyczny clickListener powoduje wyciek pamięci. Zadeklaruj odbiornik jako niestatyczny i zamiast tego powiąż go z ViewHolder.
BladeCoder
1
@AJW Najprostszym sposobem jest wcześniejsze zainicjowanie nasłuchiwania i przekazanie go jako argumentu do konstruktora Adapter, a następnie konstruktora ViewHolder.
BladeCoder,
97

Sprawdź podobne pytanie , komentarz @ CommonsWare prowadzi do tego linku , który implementuje OnClickListenerinterfejs w viewHolder.

Oto prosty przykład 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++){

        }


      }
  }

AdapterWtedy wygląda to tak:

    @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
źródło
14
To wydaje się iść w złym kierunku. Jeśli konieczne jest ponowne użycie widoku recyclingler w innym fragmencie / działaniu, adapter / viewholder definiuje teraz logikę kliknięć zamiast tego, co je zawiera. Kliknięcia powinny być obsługiwane bezpośrednio lub pośrednio przez instancję zawierającą. Wydaje się, że słuchacz dotyku jest jedynym skutecznym sposobem na osiągnięcie tego celu.
ian.shaun.thomas
18
@tencent Nie rozumiem, na czym polega problem. Jeśli sam ViewHolder zawiera wszystkie informacje dotyczące tego, jakie dane są wybierane po kliknięciu samego elementu, wówczas jedynym obowiązkiem kontenera jest wyświetlanie N elementów, a nie obsługa wyboru konkretnego i-tego elementu z N elementów. ListViewJuż problematyczne, jeśli trzeba było stworzyć listę bardziej skomplikowanych obiektów niż tylko prostych rzędach. Co zrobić, jeśli musisz obsługiwać różne zdarzenia w zależności od miejsca kliknięcia elementu w widoku listy? Masz przerąbane. Tutaj masz każdego słuchacza.
EpicPandaForce
2
Zgadzam się z @EpicPandaForce w tej sprawie. Przyszedłem również, aby głosować na tę odpowiedź po przeczytaniu części książki Commonsware na temat obsługi kliknięć w RecyclerViews. Jak dotąd działa to dla mnie świetnie.
AdamMc331,
1
findViewById jest tutaj używany tylko do tworzenia uchwytów widoków (stąd onCreateViewHolder). Uchwyt widoku ma zapobiegać znajdowaniu widoku za każdym razem, gdy element jest związany z uchwytem, ​​a nie przy pierwszym utworzeniu.
stuckj
2
getPosition()jest przestarzałe, użyj getAdapterPosition()lub getLayoutPosition()zamiast tego.
K Neeraj Lal,
94

Na podstawie odpowiedzi Jacoba Tabaka (+1 dla niego) mogłem dodać słuchacza onLongClick:

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) {
    }
}

Następnie możesz użyć tego w następujący sposób:

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
źródło
1
Trochę czasu zajęło mi dostosowanie się do mojej aplikacji oraz dostosowanie i sformatowanie kodu do standardów Java / Android, ale ostatecznie działało dobrze.
milosmns
Jak dodać animację dla długiego kliknięcia?
Jon
1
@ Eng.Fouad kliknięcie nie działa przy użyciu tego, chociaż jeśli ustawimy detektor kliknięć w adapterze, kliknięcie działa na każde rozwiązanie tego
problemu
4
Powinieneś również zastąpićpublic void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
Paolo Rotolo
Z jakiegoś powodu nie zwraca klikniętego widoku. W moim przypadku klikam pole wyboru, ale dany widok to coś innego. Sposób, w jaki sprawdzam:view.getId() == R.id.selection
dVaffection
63

To działało dla mnie. Dołącz OnClickListenerdo onBindView. Naprawdę nie wiem, czy to wpłynie na wydajność, ale wydaje się, że działa dobrze z małym kodem.

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
źródło
5
w moim przypadku holder.itemView.setOnClickListener (..)
D4rWiNS
18
w moim przypadku nazywa się on „itemView” zamiast „view”, mówiąc tylko dla początkujących, niektórzy z nich nie rozumieją, co kopiują i nie mogą zrozumieć, dlaczego to nie działa
D4rWiNS
3
Jego układ
Bubunyo Nyavor,
1
dla mnie wydaje się, że dotyczy to tylko ostatniego widocznego elementu, a nie klikniętego elementu
Nasz Njoka Sr.
2
To rozwiązanie wydaje mi się najlepsze, ale czym różni się ono od odpowiedzi @bolot pod względem wydajności? Zaimplementował View.OnClickListener bezpośrednio w klasie ViewHolder, która następnie wyrzuca metodę onClick osobno. Które byłoby najlepsze rozwiązanie?
Edmond Tamas
46

To było dla mnie tak trudne, aby mieć w działaniu nasłuchiwanie kliknięcia elementu, a także mieć nasłuchiwanie kliknięcia dla pojedynczego widoku elementu, który nie uruchomi się w nasłuchiwaniu kliknięcia elementu. Po przeanalizowaniu odpowiedzi Jacoba Tabaka szanuję jego odpowiedź za kliknięcie przedmiotu, jeśli nie zostaną przedstawione żadne inne działania dotykowe wewnątrz przedmiotu.

Mam niestandardowy OnClickListenerinterfejs, który ma zdarzenie kliknięcia elementu, które przechowuje widok klikniętego elementu i pozycję elementu z adaptera. Przedstawiam jego instancję w konstruktorze (lub może to być za pomocą settera) i dołączam do nasłuchiwania kliknięcia kontenera uchwytu widoku.

Mam także inny odbiornik kliknięć w adapterze (może znajdować się w uchwycie widoku), który obsłuży bieżące kliknięcie widoku z kontenera.

 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();
}}

W działaniu musisz zainicjować adapter, przekazując instancję pliku 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);
}

I mój 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 The First
źródło
To podejście zadziałało dla mnie dobrze - oznacza to, że możesz obsługiwać kliknięcia w działaniu, a nie w widoku siatki
obcinacz liści
3
Gdzie mogę ci dać pieniądze? 4 godziny poszukiwań, a potem przeczytałem twój post. Dziękujemy za czas poświęcony na opublikowanie tego.
Brandon
3
Brzmi głupio, ale czy ma to jakiś problem z pamięcią lub wydajnością? Ponieważ przypisujemy detektor kliknięć za każdym razem, gdy rysowany jest widok, prawda?
rgv
1
@Raghav tak za każdym razem, gdy widok jest wiązany, przypisywany jest nowy detektor kliknięć, ale jest to standardowy przepływ. Ale mOnItemClickListener jest tworzony tylko raz dla adaptera, tylko widok i jego pozycja są różne przy każdym kliknięciu elementu;)
Sir NIkolay Cesar The First
3
Świetny przykład, aby zabić wydajność aplikacji i stworzyć nadużycie pamięci! W tym przykładzie wystarczy przewinąć, aby utworzyć setki bezużytecznych obiektów, które za chwilę będą bezużyteczne i będą dostępne jako oszałamiające. @NoobDogg ma rację. Żadne ClickListenery nie muszą być tworzone w onBindView. Detektor kliknięć musi zostać utworzony raz w onCreateView (lub konstruktorze posiadaczy) i istnieje, dopóki potrzebujemy ekranu z tym adapterem.
Mykola Tychyna
36

Właśnie tego potrzebowałem, na wypadek, gdyby ktoś uznał to za przydatne:

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());
            }
        });

    }
}

Źródło: http://blog.csdn.net/jwzhangjie/article/details/36868515

Owca Fifer
źródło
Ze wszystkich wersji, które wypróbowałem, właśnie tę mam. Ale czy można to zrobić w ten sposób? Czy jest lepszy sposób, na przykład najlepsza praktyka?
Matthias Loibl
1
O ile mogłem powiedzieć, był to jedyny sposób. Sprawdź to, aby uzyskać więcej informacji! stackoverflow.com/a/24933117/1508887
Fifer Sheep
Jak mogę otworzyć nowy fragment od wewnątrz metody onclick?
hash
5
getAdapterPosition () zastępuje getPosition ()
Kennedy Nyaga
27

Mam ładne rozwiązanie RecyclerView„s onItemClickListenerdla przedmiotów i podpunktach

Krok 1 - Utwórz interfejs

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);
}

Krok 2 Następnie użyj go w onBindViewHoldermetodzie adaptera w następujący sposób

/**
     * 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);
        }

    }

Krok 3 - znajdź i skonfiguruj widok recyklera w działaniu lub fragmencie, w którym go używasz

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());

Krok 4 - W końcu zaimplementuj interfejs w działaniu lub fragmencie, w którym korzystasz z widoku recyklera

@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
źródło
2
Jest to najlepsze rozwiązanie, ponieważ zwykle potrzebujemy wielu właściwości z działania / fragmentu na naszym obiekcie onItemClickListener i nie ma sensu wywoływać go bezpośrednio z widoku (musiałbym utworzyć niestandardowy konstruktor dla każdego adaptera). Nawiasem mówiąc, twój kod jest trochę rozbudowany, sugeruję ci przyciąć go do najważniejszej części (setOnItemClickListener).
sagits
jest to dobre proste podejście do odróżnienia wiersza / przedmiotu od podpozycji
Nigel Savage
17

Oto co zrobiłem. To rozwiązanie obsługuje zarówno elementy onClick, jak i onLongClick zarówno w elementach RecyclerView, jak i widokach, wewnątrz elementów RecyclerView (widoki wewnętrzne).

Oznaczam viewHolder w wybranych widokach:

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;
}

I używam holder.getPosition (), aby pobrać pozycję w metodzie onClick () (onLongClick jest podobny):

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();
    }
}

Działa również wariant z getChildPosition. Pamiętaj, że w widokach wewnętrznych w funkcji onClick () użyj:

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

Moim zdaniem zaletą tego rozwiązania jest to, że po kliknięciu obrazu wywoływany jest tylko detektor obrazu onclick (), podczas gdy połączyłem rozwiązanie Jacoba dla widoku elementu RecyclerView i moje rozwiązanie dla widoków wewnętrznych widok elementu RecyclerView po kliknięciu ( ) jest również nazywany (po kliknięciu obrazu).

u2gilles
źródło
11

Jest to o wiele łatwiejszy sposób. Po prostu zastosuj po kliknięciu w onBindViewHolderwidoku katalogu głównego.

Pomyśl, że to twój pogląd na adapter,

<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>

Następnie wykonaj następujące czynności w adapterze

//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
źródło
9

Możesz przekazać clickListenerdo Adapter.

W twoim 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);
        }
    }
};

następnie przekaż to do Adapter:

MainAdapter mainAdapter = new MainAdapter(this, mItemClick);

W 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
źródło
Jak przekazujesz holderwartości przez zamiar?
RoCk RoCk
8

Opracowałem lekką bibliotekę dla Androida, możesz odwiedzić https://github.com/ChathuraHettiarachchi/RecycleClick

i śledź następującą próbkę

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
            }
        });
Chathura Jayanath
źródło
Potwierdzam, ta biblioteka jest świetna! Bardzo łatwy w użyciu, dobra robota!
peterkodermac
7

Możesz zaimplementować OnClickListener do swojej klasy 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());
        }
    }

I onBindViewHolder ustaw element posiadacza widoku

public void onBindViewHolder(ViewHolder holder, int position) {
        holder.tvTitle.setText(objects.get(position).getTitle());
        holder.item = objects.get(position);
        }
populacja
źródło
7

Zbyt proste i skuteczne.

Zamiast implementować interfejs View.OnClickListenerwewnątrz uchwytu widoku lub tworzyć interfejs i implementować interfejs w twojej działalności - użyłem tego kodu do uproszczenia OnClickListenerimplementacji.

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
źródło
3
Jest to powszechna zła praktyka, ponieważ wygląda na zbyt łatwą. Tworzysz nowy wewnętrzny moduł nasłuchujący za każdym razem, gdy obiekt jest powiązany (a każdy element w programie do recyklingu może być związany wiele razy), co jest niekorzystne dla a) wydajności b) wyrzucania elementów bezużytecznych. Zamiast tego należy gdzieś utworzyć JEDEN obiekt nasłuchujący (w widoku, w adapterze, w górnym fragmencie lub działaniu) i po prostu dodać go do elementów w konstruktorze widoku w onCreateViewHolder. Ma to dodatkową złożoność polegającą na tym, że trzeba dowiedzieć się, który element był klikający, ale można go łatwo rozwiązać za pomocą tagów lub dodając więcej informacji do posiadacza.
GuillermoMP,
6

Wszystkie dotychczas opublikowane odpowiedzi są świetnymi rozwiązaniami, jednak jeśli nie chcesz zajmować się zbyt wieloma szczegółami implementacji, a chcesz, aby działała podobnie do ListView, polecam użycie TwoWay-View, jak widać tutaj:

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

Zauważ, że ta implementacja obsługuje również długie naciśnięcie na przedmioty, a także obsługę stanów naciśnięcia (co jest czymś ważnym, czego brakuje innym rozwiązaniom tego pytania).

Jeśli nie chcesz korzystać z całej biblioteki, spójrz na klasę ClickItemTouchListener , która w razie potrzeby może być używana jako samodzielna. Jedyny problem, jaki w tym momencie znalazłem, to długie naciśnięcie + przewijanie, wydaje się, że ma nieprawidłowe zachowanie.

Jawnnypoo
źródło
6

Jeśli chcesz złapać zdarzenie kliknięcia na poszczególnych elementach, po prostu zaimplementuj je OnClickListenerw ViewHolderklasie, a następnie ustaw detektory kliknięć na poszczególnych widokach lub całości itemView.

Poniższy przykład pokazuje to samo

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
źródło
5

Dla mnie to najlepszy sposób:

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
źródło
3
getChildPosition () zostaje zdekapitowany
Nasz Njoka Sr.
5

RecyclerViewNie mają OnClickListeneri będą musiały wdrożyć go sami.

Chciałbym dodać OnItemClickListenerinterfejs Adapterz onClickmetodą wywoływaną po kliknięciu widoku elementu z ViewHolder. W związku z tym odpowiedzialność za zarządzanie kliknięciem elementu spoczywa poza ViewHolderi Adapter. Będzie aktywność lub fragment, który zadecyduje, co robić

Dodaj interfejs do obiektu nasłuchującego i obiektu nasłuchującego.

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

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

  ...
}

Przechwytujemy kliknięcie widoku głównego elementu i po wywołaniu wywołania zwrotnego wywołanie onClicknasłuchiwania na adapterze.

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);
              }
          });
      }
  }
}

Ponieważ aktywność lub fragment, fragment w naszym przypadku, przypisujemy odbiornik do adaptera, a wywołanie zwrotne onClick otrzymamy wybrany element według pozycji i otworzymy szczegółową aktywność elementu.

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
źródło
5

Niestety RecyclerViewbrakuje kilku ListViewwbudowanych funkcji. Na przykład możliwość dodania OnItemClickListenerwyzwalacza po kliknięciu elementu. RecyclerViewpozwala ustawić OnClickListenerw adapterze, ale przekazanie detektora kliknięć z kodu wywołującego, do adaptera i do ViewHolder, jest skomplikowane w przypadku przechwycenia prostego kliknięcia elementu.

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);
}
}

Musisz także zdefiniować R.id.item_click_supportza pomocą ids.xml:

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

Wynikowy detektor kliknięć kodu wygląda teraz tak:

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

W celu uzyskania krótkiego wyjaśnienia na temat kliknięć programu recyclinglerview zajrzyj na ten blog littlerobots_blog

anand krish
źródło
5

możesz łatwo zdefiniować setOnClickListener w swojej klasie ViewHolder w następujący sposób:

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
źródło
5

Oto, co zrobiłem Czytaj więcej i pobierz tutaj treść

Dodanie tego samego tutaj

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
źródło
4

Z większości powyższych odpowiedzi wydaje się, że ustawiają swoich onklicklistenerów na poszczególnych elementach. Jednak rozwiązanie, które zamierzam zaoferować, jest bardzo proste, ale dla wielu nie jest intuicyjne. Wielu zapomina, że ​​pozostałe komponenty są zawsze w komponencie nadrzędnym, który jest używany do wyświetlania elementów w widokach Listy lub Recyklera. To rozwiązanie polega tylko na ustawieniu pojedynczego detektora kliknięcia w tym widoku nadrzędnym i kolejka jest odtwarzana. Rozwiązanie obejmuje również sposób przekazania pozycji klikniętego elementu z widoku listy lub recyklera. Tutaj naszym głównym rootview jest CardView z biblioteki wsparcia Androida. Oto przykładowy kod

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
źródło
4

Kotlin realizacja nhaarman za odpowiedź :

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
źródło
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();
                }
            });
        }
    }
Wyjątek wskaźnika zerowego
źródło
3

tutaj jest kompletny kod dla mojego niestandardowego adaptera. Ten kod nadmuchuje wiersze elementami listy zdefiniowanymi w pliku xml o nazwie „list_item”, a także wykona zdarzenie kliknięcia na wszystkich wierszach elementów listy o odpowiednich pozycjach.

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
źródło
2

Możemy to zrobić, używając słabych referencji Java. Semantycznie uchwyt widoku to taki, który powinien odpowiadać na zdarzenie kliknięcia lub przekazać je właściwemu responderowi.

Nasze cele:

  1. Viewholder nie powinien wiedzieć nic o klasie, która reaguje na zdarzenia, poza tym, że implementuje pewien interfejs.
  2. Moduł obsługi kliknięć powinien uzyskać pozycję w widoku RecyclerView klikniętego widoku.
  3. Powinniśmy być w stanie rozpoznać, który widok został kliknięty w uchwycie widoku.
  4. Utrzymuj luźne połączenie między wszystkimi elementami i nie powoduj żadnych cykli podtrzymujących.

Kroki:

  1. Utwórz interfejs do obsługi odpowiedzi na kliknięcia.

  2. Zaimplementuj ten interfejs w działaniu, które obsłuży kliknięcie.

  3. Dodaj zmienną składową w adapterze RecyclerView, aby przechowywać słabe odniesienie i konstruktor, który ją ustawia.

  4. Zrób to samo w RecyclerView ViewHolder i dodaj zmienną składową, aby śledzić pozycję.

  5. Ustaw detektory kliknięć w dowolnym widoku, który chcesz w ViewHolder, a następnie oddzwoń do odpowiadającego, aby je obsłużył.

  6. Zmień metodę onBindViewHolder, aby ustawić pozycję podczas wiązania.

  7. Przekaż obiekt odpowiadający w dół do ViewHolder.

  8. W odpowiedzi możesz teraz użyć getId () w widoku, aby dowiedzieć się, który widok został kliknięty.

A oto Gist, dzięki czemu możesz zobaczyć, jak to wszystko do siebie pasuje: obsługa kliknięć RecyclerView

Rajiev Timal
źródło
2

Zdaję sobie sprawę, że jest wiele odpowiedzi, ale pomyślałem, że mógłbym również przedstawić moją implementację. (Pełne informacje można znaleźć na inne pytanie, na które odpowiedziałem ).

Aby dodać detektor kliknięć, ViewHolderklasa wewnętrzna musi się zaimplementować View.OnClickListener. To dlatego, że można ustawić OnClickListenerw itemViewparametrze ViewHolder„s konstruktora. Pokażę ci, co mam na myśli:

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());
        }
    }
}

Jedyne inne rzeczy, które musisz dodać, to niestandardowy interfejs dla Twojej Adapteri metody ustawiającej:

private OnEntryClickListener mOnEntryClickListener;

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

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

Tak więc Twoja nowa obsługa kliknięć Adapterjest zakończona.

Teraz użyjmy go ...

    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
        }
    });

Jest to w zasadzie sposób skonfigurowania normalnego Adapter, z tą różnicą, że używasz utworzonej przez ciebie metody ustawiającej, aby kontrolować, co zrobisz, gdy użytkownik kliknie określoną pozycję na liście.

Możesz także przejrzeć zestaw przykładów, które podałem w tej Gist na GitHub:

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

Farbod Salamat-Zadeh
źródło
Powinieneś użyć getAdapterPosition () zamiast getLayoutPosition ()
BladeCoder
2

To właśnie robię, aby ponownie wykorzystać OnClickListener

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

w ViewHoder Weźmy element nadrzędny itemlayout

  public class MyviewHolder extends RecyclerView.ViewHolder {

       LinearLayout linearLayout_item;

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

w onBindViewHolder ustaw znacznik jako pozycję

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

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

i w 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
źródło
2

Dla mnie czysty sposób to zrobić.

Konstruktor adapterów

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;
        }
}

Połączony interfejs

private interface EnvironmentTypeRecyclerViewAdapterListener
{
    void onListItemSelected(Environment environment);
}
Jeremie Petitjean
źródło