RecyclerView neden onItemClickListener () 'a sahip değil?


965

Ben keşfetmek oldu RecyclerViewve bunu görmek şaşırdı RecyclerViewyoktur onItemClickListener().

İki sorum var.

Ana soru

Google'ın neden kaldırıldığını bilmek istiyorum onItemClickListener()?

Bir performans sorunu veya başka bir şey var mı?

İkincil Soru

Sorunumu benim yazarak onClickçözdüm RecyclerView.Adapter:

public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {

    public TextView txtViewTitle;
    public ImageView imgViewIcon;

    public ViewHolder(View itemLayoutView) {
        super(itemLayoutView);
        txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
        imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
    }

    @Override
    public void onClick(View v) {

    }
}

Bu iyi mi / daha iyi bir yolu var mı?


31
Kodunuzun çalışması için itemLayoutView.setOnClickListener (this); ViewHolder yapıcısında.
whitneyland

3
güzel bir soru sordunuz ... birçok geliştirici RecyclerView ve ListView hakkında aynı şüpheye sahip.
venkat

17
Soru: RecyclerView'de neden OnItemClickListner () yoktur? 2 dışındaki tüm cevaplar: RecyclerView için onclick nasıl eklenir
Manohar Reddy

2
Birisi aslında cevaplamak için zaman aldıQUESTION
Ojonugwa Jude Ochalifu

1
Performans ve çöp bellek sorunları nedeniyle kaldırdıklarını düşünüyorum. Ama kabul edilen cevaba bakın .... aynı problemleri yaratacaktır. Sanırım kabul ederek hata yaptın ve şimdi diğer ppls senin yüzünden hatalar yapıyor :).
Alex

Yanıtlar:


1207

tl; dr 2016 Tıklamalar için bir Gözlemlenebilir göstermek üzere RxJava ve PublishSubject öğelerini kullanın.

public class ReactiveAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    String[] mDataset = { "Data", "In", "Adapter" };

    private final PublishSubject<String> onClickSubject = PublishSubject.create();

    @Override 
    public void onBindViewHolder(final ViewHolder holder, int position) {
        final String element = mDataset[position];

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
               onClickSubject.onNext(element);
            }
        });
    }

    public Observable<String> getPositionClicks(){
        return onClickSubject.asObservable();
    }
}

Orijinal Mesaj:

Girişinden bu yana ListView,onItemClickListener sorunlu olmuştur. İç öğelerin herhangi biri için bir tıklama dinleyicisine sahip olduğunuz anda geri arama tetiklenmeyecektir, ancak bildirilmemiştir veya iyi belgelenmemiştir (eğer varsa), bu yüzden çok fazla karışıklık ve SO soruları vardı.

RecyclerViewBunun bir adım daha ileri götürdüğü ve bir satır / sütun kavramına sahip olmadığı, ancak keyfi olarak ortaya konan miktarda çocuk olduğu göz önüne alındığında , onClick'i her birine veya programcı uygulamasına devretti.

1: 1 değiştirme olarak değil, karmaşık kullanım durumları için daha esnek bir bileşen Recyclerviewolarak düşünün ListView. Ve dediğin gibi, çözümünüz Google'ın sizden beklediği şey. Şimdi onClick'i yapıcı üzerinde geçirilen bir arabirime devredebilen bir bağdaştırıcınız var, bu da hem ListViewve için doğru kalıptır Recyclerview.

public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {

    public TextView txtViewTitle;
    public ImageView imgViewIcon;
    public IMyViewHolderClicks mListener;

    public ViewHolder(View itemLayoutView, IMyViewHolderClicks listener) {
        super(itemLayoutView);
        mListener = listener;
        txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
        imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
        imgViewIcon.setOnClickListener(this);
        itemLayoutView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v instanceof ImageView){
           mListener.onTomato((ImageView)v);
        } else {
           mListener.onPotato(v);
        }
    }

    public static interface IMyViewHolderClicks {
        public void onPotato(View caller);
        public void onTomato(ImageView callerImage);
    }

}

ve daha sonra adaptörünüzde

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

   String[] mDataset = { "Data" };

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

       MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() { 
           public void onPotato(View caller) { Log.d("VEGETABLES", "Poh-tah-tos"); };
           public void onTomato(ImageView callerImage) { Log.d("VEGETABLES", "To-m8-tohs"); }
        });
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager) 
    @Override 
    public void onBindViewHolder(ViewHolder holder, int position) {
        // Get element from your dataset at this position 
        // Replace the contents of the view with that element 
        // Clear the ones that won't be used
        holder.txtViewTitle.setText(mDataset[position]);
    } 

    // Return the size of your dataset (invoked by the layout manager) 
    @Override 
    public int getItemCount() { 
        return mDataset.length;
    } 
  ...

Şimdi bu son kod parçasına bakın: onCreateViewHolder(ViewGroup parent, int viewType)İmza zaten farklı görünüm türleri öneriyor. Her biri için farklı bir izleyiciye de ihtiyacınız olacak ve daha sonra her birinin farklı bir tıklama grubu olabilir. Veya yalnızca herhangi bir görünüm alan ve bir görünüm alan ve onClickListenerbuna göre uygulanan genel bir görüntüleyici oluşturabilirsiniz . Veya birkaç bölüm / etkinlik farklı tıklama davranışlarıyla aynı listeye sahip olacak şekilde bir düzey orkestratöre yetki verin. Yine, tüm esneklik yanınızda.

Bu gerçekten ihtiyaç duyulan bir bileşendir ve ListViewşimdiye kadar iç uygulamalarımızın ve geliştirmelerimizin ne olduğuna oldukça yakındır . Google'ın nihayetinde kabul etmesi iyi bir şey.


78
RecyclerView.ViewHolder bir getPosition () yöntemine sahiptir. Bu kodda bazı ayarlamalar yaparak, konumu dinleyiciye iletebilirsiniz.
se_bastiaan

13
Bilginin onBindViewHolder(holder, position)doldurulması gereken yer tamamen kaçırdı .
MLProgrammer-CiM

26
@se_bastiaan getPosition()kullanımdan kaldırıldı "Bağdaştırıcı güncellemelerinin zaman uyumsuz * işlenmesi nedeniyle anlamı belirsiz olduğu için bu yöntem kullanımdan kaldırıldı. Lütfen kullanım durumunuza bağlı olarak {@link #getLayoutPosition ()} veya * {@link #getAdapterPosition ()} kullanın. "
Mart'ta upenpat

8
Birkaç seçeneğiniz var. Konumu görüntüleyicinin içindeki bir int alanına koymak, bağlayıcıyken güncellemek, ardından tıklamaya döndürmek birdir.
MLProgrammer-CiM

8
@ MLProgrammer-CiM "Birkaç seçeneğiniz var. Konumu izleyicinin içindeki bir int alanına koymak, ciltleme sırasında güncellemek, ardından tıklamayla döndürmek birdir." ViewHolder zaten bu değere sahiptir ve zaten ayarlanmıştır. Sadece araviewHolder.getPosition();
Chad Bingham

104

RecyclerView neden hiç onItemClickListener

RecyclerViewEski aksine, bir araç kutusu ListViewo özellikler ve daha fazla esneklik daha az yapı vardır. onItemClickListenerListView çıkarıldıktan tek özelliği değildir. Ama onu beğeninize göre genişletmek için çok fazla dinleyici ve yöntem var, sağ elinde çok daha güçlü;).

Bence çıkarıldı en karmaşık özellik RecyclerViewolan Hızlı Kaydırma . Diğer özelliklerin çoğu kolayca yeniden uygulanabilir.

Başka hangi harika özelliklerin RecyclerVieweklendiğini bilmek istiyorsanız, bu yanıtı başka bir soruya okuyun .

Bellek verimliliği - onItemClickListener için bırakma çözümü

Bu çözüm , bir Android GDE olan Hugo Visser tarafından piyasaya sürüldükten hemen sonra önerildi . Kodunuzu bırakmanız ve kullanmanız için lisanssız bir sınıf hazırladı.RecyclerView

O ile tanıtıldı yönlülük bazı vitrin RecyclerViewyararlanarak RecyclerView.OnChildAttachStateChangeListener.

Edit 2019 : kotlin benim tarafımdan, java one, Hugo Visser, aşağıda tutuldu

Kotlin / Java

Bir dosya oluşturun values/ids.xmlve bunu içine koyun:

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

sonra aşağıdaki kodu kaynağınıza ekleyin

Kotlin

Kullanımı:

recyclerView.onItemClick { recyclerView, position, v ->
    // do it
}

(ayrıca eklediğim başka bir özellik için uzun öğe tıklamasını destekler ve aşağıya bakın).

uygulama (Hugo Visser Java koduna uyarlamam):

typealias OnRecyclerViewItemClickListener = (recyclerView: RecyclerView, position: Int, v: View) -> Unit
typealias OnRecyclerViewItemLongClickListener = (recyclerView: RecyclerView, position: Int, v: View) -> Boolean

class ItemClickSupport private constructor(private val recyclerView: RecyclerView) {

    private var onItemClickListener: OnRecyclerViewItemClickListener? = null
    private var onItemLongClickListener: OnRecyclerViewItemLongClickListener? = null

    private val attachListener: RecyclerView.OnChildAttachStateChangeListener = object : RecyclerView.OnChildAttachStateChangeListener {
        override fun onChildViewAttachedToWindow(view: View) {
            // every time a new child view is attached add click listeners to it
            val holder = this@ItemClickSupport.recyclerView.getChildViewHolder(view)
                    .takeIf { it is ItemClickSupportViewHolder } as? ItemClickSupportViewHolder

            if (onItemClickListener != null && holder?.isClickable != false) {
                view.setOnClickListener(onClickListener)
            }
            if (onItemLongClickListener != null && holder?.isLongClickable != false) {
                view.setOnLongClickListener(onLongClickListener)
            }
        }

        override fun onChildViewDetachedFromWindow(view: View) {

        }
    }

    init {
        // the ID must be declared in XML, used to avoid
        // replacing the ItemClickSupport without removing
        // the old one from the RecyclerView
        this.recyclerView.setTag(R.id.item_click_support, this)
        this.recyclerView.addOnChildAttachStateChangeListener(attachListener)
    }

    companion object {
        fun addTo(view: RecyclerView): ItemClickSupport {
            // if there's already an ItemClickSupport attached
            // to this RecyclerView do not replace it, use it
            var support: ItemClickSupport? = view.getTag(R.id.item_click_support) as? ItemClickSupport
            if (support == null) {
                support = ItemClickSupport(view)
            }
            return support
        }

        fun removeFrom(view: RecyclerView): ItemClickSupport? {
            val support = view.getTag(R.id.item_click_support) as? ItemClickSupport
            support?.detach(view)
            return support
        }
    }

    private val onClickListener = View.OnClickListener { v ->
        val listener = onItemClickListener ?: return@OnClickListener
        // ask the RecyclerView for the viewHolder of this view.
        // then use it to get the position for the adapter
        val holder = this.recyclerView.getChildViewHolder(v)
        listener.invoke(this.recyclerView, holder.adapterPosition, v)
    }

    private val onLongClickListener = View.OnLongClickListener { v ->
        val listener = onItemLongClickListener ?: return@OnLongClickListener false
        val holder = this.recyclerView.getChildViewHolder(v)
        return@OnLongClickListener listener.invoke(this.recyclerView, holder.adapterPosition, v)
    }

    private fun detach(view: RecyclerView) {
        view.removeOnChildAttachStateChangeListener(attachListener)
        view.setTag(R.id.item_click_support, null)
    }

    fun onItemClick(listener: OnRecyclerViewItemClickListener?): ItemClickSupport {
        onItemClickListener = listener
        return this
    }

    fun onItemLongClick(listener: OnRecyclerViewItemLongClickListener?): ItemClickSupport {
        onItemLongClickListener = listener
        return this
    }

}

/** Give click-ability and long-click-ability control to the ViewHolder */
interface ItemClickSupportViewHolder {
    val isClickable: Boolean get() = true
    val isLongClickable: Boolean get() = true
}

// Extension function
fun RecyclerView.addItemClickSupport(configuration: ItemClickSupport.() -> Unit = {}) = ItemClickSupport.addTo(this).apply(configuration)

fun RecyclerView.removeItemClickSupport() = ItemClickSupport.removeFrom(this)

fun RecyclerView.onItemClick(onClick: OnRecyclerViewItemClickListener) {
    addItemClickSupport { onItemClick(onClick) }
}
fun RecyclerView.onItemLongClick(onLongClick: OnRecyclerViewItemLongClickListener) {
    addItemClickSupport { onItemLongClick(onLongClick) }
}

(aşağıya bakın ayrıca bir XML dosyası eklemeniz gerekir)

Kotlin versiyonunun bonus özelliği

Bazen RecyclerView öğesinin tüm öğelerinin tıklanabilir olmasını istemezsiniz.

Bunun üstesinden gelmek için hangi öğenin tıklanabilir olduğunu kontrol ItemClickSupportViewHolderetmek ViewHolderiçin kullanabileceğiniz arayüzü tanıttım.

Misal:

class MyViewHolder(view): RecyclerView.ViewHolder(view), ItemClickSupportViewHolder {
    override val isClickable: Boolean get() = false
    override val isLongClickable: Boolean get() = false
}

Java

Kullanımı:

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

(ayrıca uzun öğe tıklama destekler)

Uygulama (benim tarafımdan eklenen yorumlar):

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) {
                // ask the RecyclerView for the viewHolder of this view.
                // then use it to get the position for the adapter
                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) {
            // every time a new child view is attached add click listeners to it
            if (mOnItemClickListener != null) {
                view.setOnClickListener(mOnClickListener);
            }
            if (mOnItemLongClickListener != null) {
                view.setOnLongClickListener(mOnLongClickListener);
            }
        }

        @Override
        public void onChildViewDetachedFromWindow(View view) {

        }
    };

    private ItemClickSupport(RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
        // the ID must be declared in XML, used to avoid
        // replacing the ItemClickSupport without removing
        // the old one from the RecyclerView
        mRecyclerView.setTag(R.id.item_click_support, this);
        mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
    }

    public static ItemClickSupport addTo(RecyclerView view) {
        // if there's already an ItemClickSupport attached
        // to this RecyclerView do not replace it, use it
        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);
    }
}

Nasıl çalışır (neden etkilidir)

Bu sınıf, bir takılarak çalışır RecyclerView.OnChildAttachStateChangeListeneriçin RecyclerView. Bu dinleyici, bir çocuk her takıldığında veya çocuktan ayrıldığında bildirilir RecyclerView. Kod, görünüme bir dokunma / uzun tıklama dinleyicisi eklemek için bunu kullanır. Dinleyici RecyclerView, RecyclerView.ViewHolderhangisinin pozisyonu içerdiğini sor .

Bu, diğer çözümlerden daha verimlidir çünkü her görünüm için birden fazla dinleyici oluşturmaktan kaçınır ve RecyclerViewkaydırılırken onları yok etmeye ve oluşturmaya devam eder .

Kodu, daha fazlasına ihtiyacınız varsa sahibinin kendisini size geri vermesi için de uyarlayabilirsiniz.

Son açıklama

Listenizin her görünümünde önerilen diğer yanıtlar gibi bir tıklama dinleyici ayarlayarak adaptörünüzde işlemenin TAMAMEN iyi olduğunu unutmayın.

Yapılması gereken en etkili şey bu değil (her görünümü yeniden kullandığınızda yeni bir dinleyici oluşturuyorsunuz) ama işe yarıyor ve çoğu durumda bu bir sorun değil.

Ayrıca, endişelerin ayrılmasına karşı birazdır, çünkü aslında tıklama olaylarını devretmek için Adaptörün İşi değildir.


addOnChildAttachStateChangeListener yapıcı içinde ve asla kaldırmak?
Saba

@Saba, yapıcıyı doğrudan kullanmamanız gereken statik yöntemler addTo()ve removeFrom(). Örnek, geri dönüşüm görüntüleme etiketiyle ilişkilendirilir ve onunla veya manuel olarak kaldırıldığında ölür.
Daniele Segato

Tek yapmanız gereken tek bir tıklama dinleyicisini ayarlamak onCreateViewHolderve bu kadar.
EpicPandaForce

Argümanınız akıyor, kod miktarı değil, verimlilik ve sorumluluk prensibi ile ilgili ve kod miktarı, özellikle bu kod tekrar kullanılabilir ve verimli olduğunda iyi / kötü çözümün büyük bir göstergesi değil. Bu kodu projenize koyduktan sonra (ki bu bir kütüphane katılımı olarak düşünebilirsiniz) ihtiyacınız olan tek şey sizin için 1-astar RecyclerView.
Daniele Segato

@DanieleSegato Bunun için çok teşekkür ederim!
Bay Octodood

90

Bu şekilde seviyorum ve kullanıyorum

içeride

public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)

Koymak

View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_image_and_text, parent, false);
v.setOnClickListener(new MyOnClickListener());

Ve bu sınıfı istediğiniz yerde oluşturun

class MyOnClickListener implements View.OnClickListener {
    @Override
    public void onClick(View v) {
       int itemPosition = recyclerView.indexOfChild(v);
       Log.e("Clicked and Position is ",String.valueOf(itemPosition));
    }
}

Daha önce okudum daha iyi bir yol var ama bu yol kolay ve karmaşık değil gibi.


23
büyük olasılıkla MyOnClickListenerörnek değişkeni haline getirmelidir , çünkü her zaman newAnahtar Kelime ile yeni bir örnek oluşturacaksınız
user2968401

14
recyclerView.getChildPosition (h); artık depricated recyclerView kullanın. indexOfChild (h);
Kadir Hüseyin

4
Kaydırma sırasında sorun yaşamıyor musunuz? Testlerimde itemPosition, görünümlerin geri dönüşümüne bağlı gibi görünüyor, bu nedenle adaptördeki tam listeme kıyasla yanlış gidiyor.
Simon

16
recyclerViewMyOnClickListener'a nasıl ulaşılır?
guo

3
Kullanmak yerine: int itemPosition = recyclerView.indexOfChild (v); kullanmanız gerekir: RecyclerView.ViewHolder tutucu = recyclerView.getChildViewHolder (v); int itemPosition = holder.getAdapterPosition ();
Gordon Freeman

35

Android Recyclerview ile onItemClickListener, Neden sadece çalışamıyorum çalışıyorum ListView.

Kaynak: Link

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {

private OnItemClickListener mListener;
public interface OnItemClickListener {
    public void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }
    });
}
@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) {

  }
}

Ve bunu RecyclerView olarak ayarlayın:

    recyclerView = (RecyclerView)rootView. findViewById(R.id.recyclerView);
    RecyclerView.LayoutManager mLayoutManager = new            LinearLayoutManager(getActivity());
    recyclerView.setLayoutManager(mLayoutManager);
    recyclerView.addOnItemTouchListener(
            new RecyclerItemClickListener(getActivity(), new   RecyclerItemClickListener.OnItemClickListener() {
                @Override
                public void onItemClick(View view, int position) {
                    // TODO Handle item click
                    Log.e("@@@@@",""+position);
                }
            })
    );

7
Dürüst olmak için zarif değil.
vishal dharankar

@vishaldharankar neden olmasın? Bence kullandıktan sonra odak değişimi çatışmasından kaçınmanın en iyi yoluSwipeRefreshLayout
NickUnuchek

Bu tamamen gereksizdir, dokunmaya müdahale etmek yerine View.OnClickListener kullanabilirsiniz.
EpicPandaForce

23

@Marmor sayesinde cevabımı güncelledim.

ViewHolder sınıf yapıcısında onClick () işlemek ve OnItemClickListener arabirimi aracılığıyla üst sınıfa geçirmek için iyi bir çözüm olduğunu düşünüyorum .

MyAdapter.java

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

private LayoutInflater layoutInflater;
private List<MyObject> items;
private AdapterView.OnItemClickListener onItemClickListener;

public MyAdapter(Context context, AdapterView.OnItemClickListener onItemClickListener, List<MyObject> items) {
    layoutInflater = LayoutInflater.from(context);
    this.items = items;
    this.onItemClickListener = onItemClickListener;
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = layoutInflater.inflate(R.layout.my_row_layout, parent, false);
    return new ViewHolder(view);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    MyObject item = items.get(position);
}

public MyObject getItem(int position) {
    return items.get(position);
}


class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    private TextView title;
    private ImageView avatar;

    public ViewHolder(View itemView) {
        super(itemView);
        title = itemView.findViewById(R.id.title);
        avatar = itemView.findViewById(R.id.avatar);

        title.setOnClickListener(this);
        avatar.setOnClickListener(this);
        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        //passing the clicked position to the parent class
        onItemClickListener.onItemClick(null, view, getAdapterPosition(), view.getId());
    }
}
}

Adaptörün diğer sınıflarda kullanımı:

MyFragment.java

public class MyFragment extends Fragment implements AdapterView.OnItemClickListener {

private RecyclerView recycleview;
private MyAdapter adapter;

    .
    .
    .

private void init(Context context) {
    //passing this fragment as OnItemClickListener to the adapter
    adapter = new MyAdapter(context, this, items);
    recycleview.setAdapter(adapter);
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    //you can get the clicked item from the adapter using its position
    MyObject item = adapter.getItem(position);

    //you can also find out which view was clicked
    switch (view.getId()) {
        case R.id.title:
            //title view was clicked
            break;
        case R.id.avatar:
            //avatar view was clicked
            break;
        default:
            //the whole row was clicked
    }
}

}

34
Bu, kaydırma yaparken tonlarca nesne oluşturacak ve çöp toplayacak, bunun yerine bir OnClickListener oluşturmalı ve tekrar kullanmalısınız
marmor

2
Ayrıca onBindViewHolder()kaydırma sırasında aynı görünüm için birçok kez çağrılır. Tek bir çağrı OnClickListenerbile yardımcı olmaz çünkü OnClickListenerher çağrıyı sıfırlarsınız onBindViewHolder(). Bunun yerine @ MLProgrammer-CiM çözümüne bakın.
vovahost

Ayrıca @ MLProgrammer-CiM çözümünü geliştirebilirsiniz ve bu satırdaki her Görünüm için bir dinleyici nesnesi oluşturmak yerine MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() ....tüm görünümler için tek bir dinleyici oluşturabilirsiniz.
vovahost

21

Çocuklar bu kodu ana faaliyetinizde kullanırlar. Çok Verimli Yöntem

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.users_list);            
UsersAdapter adapter = new UsersAdapter(users, this);
recyclerView.setAdapter(adapter);
adapter.setOnCardClickListner(this);

Bağdaştırıcı sınıfınız.

public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.UserViewHolder> {
        private ArrayList<User> mDataSet;
        OnCardClickListner onCardClickListner;


        public UsersAdapter(ArrayList<User> mDataSet) {
            this.mDataSet = mDataSet;
        }

        @Override
        public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_row_layout, parent, false);
            UserViewHolder userViewHolder = new UserViewHolder(v);
            return userViewHolder;
        }

        @Override
        public void onBindViewHolder(UserViewHolder holder, final int position) {
            holder.name_entry.setText(mDataSet.get(position).getUser_name());
            holder.cardView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onCardClickListner.OnCardClicked(v, position);
                }
            });
        }

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

        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
        }


        public static class UserViewHolder extends RecyclerView.ViewHolder {
            CardView cardView;
            TextView name_entry;

            public UserViewHolder(View itemView) {
                super(itemView);
                cardView = (CardView) itemView.findViewById(R.id.user_layout);
                name_entry = (TextView) itemView.findViewById(R.id.name_entry);
             }
        }

        public interface OnCardClickListner {
            void OnCardClicked(View view, int position);
        }

        public void setOnCardClickListner(OnCardClickListner onCardClickListner) {
            this.onCardClickListner = onCardClickListner;
        }
    }

Bundan sonra etkinliğinizde bu geçersiz kılma yöntemini alırsınız.

@Override
    public void OnCardClicked(View view, int position) {
        Log.d("OnClick", "Card Position" + position);
    }

5
Kullanıcı yukarı ve aşağı kaydırma merak ediyorum, OnClickListener tekrar tekrar oluşturmak ve geri dönüşüm olacak, verimli?
Vinh.TV

Kartın güncellenmiş konumunu almak için bu küçük şeyden ödün verilebilir.
waqas ali

merhaba arkadaşım onun çalışma cazibesi güzel, ben başlangıçta kategoriler ve ürünler ile bir gereksinim aktivitesi var, kullanıcı kategori simgesini seçerseniz ben iletişim kutusu veya aktivite kategorileri görüntülemek gerekiyorsa kullanıcı ilk faaliyet için herhangi bir kategori tabanlı thata yük filtrelenmiş veri seçin lütfen bana yardım edin nasıl çözülür
Harsha

1: OnCardClickListner arabiriminde OnCardClickListner arabiriminde OnProductClicked adlı bir yöntem eklemelisiniz OnCardClickListner {void OnCardClicked (Görünüm görünümü, int konumu); void OnProductClicked (Görünüm görünümü, int konumu); } 2: Ardından, ürün simgenize bunun gibi tıklama dinleyici uygulayın. holder.yourProductIcon.setOnClickListener (yeni View.OnClickListener () {@Kamusal boşluğu geçersiz kıl onClick (View v) {onCardClickListner.OnProductClicked (v, konum);}});
waqas ali

OnCardClicked'i geçersiz kılamıyorum. İnsanlar bu cevabı nasıl destekliyor?
The_Martian

19

> RecyclerView ile Listview arasındaki fark nedir?

Bir fark var olmasıdır LayoutManagersize yönetebileceğiniz tarafından RecyclerView ile sınıf RecyclerViewgibi-

Yatay veya Dikey kaydırmaLinearLayoutManager

GridLayout tarafından GridLayoutManager

Aşamalı Izgara StaggeredGridLayoutManager

RecyclerView- için yatay kaydırma

LinearLayoutManager llm = new LinearLayoutManager(context);
llm.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(llm);

15

Takibi MLProgrammer-CIM mükemmel RxJava çözümü

Tıklamaları tüket / gözlemle

Consumer<String> mClickConsumer = new Consumer<String>() {
        @Override
        public void accept(@NonNull String element) throws Exception {
            Toast.makeText(getApplicationContext(), element +" was clicked", Toast.LENGTH_LONG).show();
        }
    };

ReactiveAdapter rxAdapter = new ReactiveAdapter();
rxAdapter.getPositionClicks().subscribe(mClickConsumer);

RxJava 2. +

Orijinal tl; dr'i şu şekilde değiştirin:

public Observable<String> getPositionClicks(){
    return onClickSubject;
}

PublishSubject#asObservable()kaldırıldı. Sadece dönmek PublishSubjectbir olan Observable.


Lütfen biraz açıklarsanız mClickConsumer'ı ikinci satırda nereden alıyorsunuz? . rxAdapter.getPositionClicks () (mClickConsumer) abone;
bluetoothfx

14

Hepsini bir araya getirme örneği ...

  • onClick () işleme
  • İmleç - RecyclerView
  • ViewHolder türleri

    public class OrderListCursorAdapter extends CursorRecyclerViewAdapter<OrderListCursorAdapter.ViewHolder> {
    
    private static final String TAG = OrderListCursorAdapter.class.getSimpleName();
    private static final int ID_VIEW_HOLDER_ACTUAL = 0;
    private static final int ID_VIEW_HOLDER = 1;
    
    public OrderListCursorAdapter(Context context, Cursor cursor) {
        super(context, cursor);
    }
    
    public static class ViewHolderActual extends ViewHolder {
        private static final String TAG = ViewHolderActual.class.getSimpleName();
        protected IViewHolderClick listener;
        protected Button button;
    
        public ViewHolderActual(View v, IViewHolderClick listener) {
            super(v, listener);
            this.listener = listener;
            button = (Button) v.findViewById(R.id.orderList_item_button);
            button.setOnClickListener(this);
        }
    
        public void initFromData(OrderData data) {
            Log.d(TAG, "><initFromData(data=" + data + ")");
            orderId = data.getId();
            vAddressStart.setText(data.getAddressStart());
            vAddressEnd.setText(data.getAddressEnd());
        }
    
        @Override
        public void onClick(View view) {
            if (view instanceof Button) {
                listener.onButtonClick((Button) view, getPosition(), this);
            } else {
                super.onClick(view);
            }
        }
    
        public interface IViewHolderClick extends ViewHolder.IViewHolderClick {
            public void onButtonClick(Button button, int position, ViewHolder viewHolder);
        }
    }
    
    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private static final String TAG = ViewHolder.class.getSimpleName();
        protected long orderId;
        protected IViewHolderClick listener;
        protected TextView vAddressStart;
        protected TextView vAddressEnd;
        protected TextView vStatus;
    
        public ViewHolder(View v, IViewHolderClick listener) {
            super(v);
            this.listener = listener;
            v.setOnClickListener(this);
    
            vAddressStart = (TextView) v.findViewById(R.id.addressStart);
            vAddressEnd = (TextView) v.findViewById(R.id.addressEnd);
            vStatus = (TextView) v.findViewById(R.id.status);
        }
    
        public void initFromData(OrderData data) {
            Log.d(TAG, "><initFromData(data=" + data + ")");
            orderId = data.getId();
            vAddressStart.setText(data.getAddressStart());
            vAddressEnd.setText(data.getAddressEnd());
        }
    
        public long getOrderId() {
            return orderId;
        }
    
        @Override
        public void onClick(View view) {
            listener.onCardClick(view, getPosition(), this);
        }
    
        public interface IViewHolderClick {
            public void onCardClick(View view, int position, ViewHolder viewHolder);
        }
    }
    
    @Override
    public int getItemViewType(int position) {
        return position == 0 ? ID_VIEW_HOLDER_ACTUAL : ID_VIEW_HOLDER;
    }
    
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Log.d(TAG, ">>onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")");
    
        ViewHolder result;
    
        switch (viewType) {
            case ID_VIEW_HOLDER_ACTUAL: {
                View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout_actual, parent, false);
                result = new ViewHolderActual(itemView, new ViewHolderActual.IViewHolderClick() {
                    @Override
                    public void onCardClick(View view, int position, ViewHolder viewHolder) {
                        Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
                        Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
                        intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
                        view.getContext().startActivity(intent);
                    }
    
                    @Override
                    public void onButtonClick(Button button, int position, ViewHolder viewHolder) {
                        Log.d(TAG, "><onButtonClick(button=" + button + ", position=" + position + ", viewHolder=" + viewHolder + ")");
                        Intent intent = new Intent(button.getContext(), OrderMapActivity.class);
                        intent.putExtra(OrderMapActivity.ARG_ORDER_ID, viewHolder.getOrderId());
                        button.getContext().startActivity(intent);
                    }
                });
                break;
            }
            case ID_VIEW_HOLDER:
            default: {
                View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false);
                result = new ViewHolder(itemView, new ViewHolder.IViewHolderClick() {
                    @Override
                    public void onCardClick(View view, int position, ViewHolder viewHolder) {
                        Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
                        Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
                        intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
                        view.getContext().startActivity(intent);
                    }
                });
                break;
            }
        }
    
        Log.d(TAG, "<<onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")= " + result);
        return result;
    }
    
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) {
        Log.d(TAG, "><onBindViewHolder(viewHolder=" + viewHolder + ", cursor=" + cursor + ")");
        final OrderData orderData = new OrderData(cursor);
        viewHolder.initFromData(orderData);
    }
    }

11

MLProgrammer-CiM cevabını anladığım kadarıyla , sadece bunu yapmak mümkündür:

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
    private ImageView image;
    private TextView title;
    private TextView price;

    public MyViewHolder(View itemView) {
        super(itemView);
        image = (ImageView)itemView.findViewById(R.id.horizontal_list_image);
        title = (TextView)itemView.findViewById(R.id.horizontal_list_title);
        price = (TextView)itemView.findViewById(R.id.horizontal_list_price);
        image.setOnClickListener(this);
        title.setOnClickListener(this);
        price.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
        Toast.makeText(context, "Item click nr: "+getLayoutPosition(), Toast.LENGTH_SHORT).show();
    }
}

9

@ MLProgrammer-CiM'nin cevabını okuduktan sonra , benim kodum:

class NormalViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

    @Bind(R.id.card_item_normal)
    CardView cardView;

    public NormalViewHolder(View itemView) {
        super(itemView);
        ButterKnife.bind(this, itemView);
        cardView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if(v instanceof CardView) {
            // use getAdapterPosition() instead of getLayoutPosition()
            int itemPosition = getAdapterPosition();
            removeItem(itemPosition);
        }
    }
}

"Hiçbir pozisyon" için getAdapterPositiongeri dönebilir sakının -1.
EpicPandaForce

9

Bu şekilde yaptım, çok basit:

Tıklanan RecyclerView konumu için 1 Satır ekleyin :

int position = getLayoutPosition()

ViewHolder sınıfı için tam kod :

private class ChildViewHolder extends RecyclerView.ViewHolder {
        public ImageView imageView;
        public TextView txtView;

        public ChildViewHolder(View itemView) {
            super(itemView);
            imageView= (ImageView)itemView.findViewById(R.id.imageView);
            txtView= (TextView) itemView.findViewById(R.id.txtView);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Log.i("RecyclerView Item Click Position", String.valueOf(getLayoutPosition()));
                }
            });
        }
    }

Umarım bu size yardımcı olacaktır.


Bunun getAdapterPositionyerine kullanmalısınız getLayoutPosition. Karşı çıkın -1.
EpicPandaForce

7

RecyclerView bir niyet başlatmak için bu yöntemi kullanın:

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

    final MyClass myClass = mList.get(i);
    viewHolder.txtViewTitle.setText(myclass.name);
   ...
    viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
      @Override
       public void onClick(View v){
             Intent detailIntent = new Intent(mContext, type.class);                                                            
             detailIntent.putExtra("MyClass", myclass);
             mContext.startActivity(detailIntent);
       }
}
);

İyi bir yol değil. Çünkü yöntemlerden onBindViewHolder(...)sonra çağrılmaz notify(). Böylece, bazı durumlarda yanlış tıklama konumu elde edebilirsiniz.
Alex Kisel

5

RecyclerView, görünümlerin geri dönüştürülmesinden (sürpriz!) onItemClickListenerRecyclerView'den sorumlu olduğu için sahip değildir , bu nedenle aldığı tıklama etkinliklerini işlemek için geri dönüştürülen görünümün sorumluluğundadır.

Bu, özellikle birden fazla yerde tıklanabilecek öğeleriniz varsa, kullanımı çok daha kolay hale getirir.


Her neyse, bir RecyclerView öğesinin tıklandığını algılamak çok kolaydır. Tek yapmanız gereken bir arayüz tanımlamaktır (Kotlin kullanmıyorsanız, bu durumda sadece bir lambda geçirirsiniz):

public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private final Clicks clicks;

    public MyAdapter(Clicks clicks) {
        this.clicks = clicks;
    }

    private List<MyObject> items = Collections.emptyList();

    public void updateData(List<MyObject> items) {
        this.items = items;
        notifyDataSetChanged(); // TODO: use ListAdapter for diffing instead if you need animations
    }

    public interface Clicks {
        void onItemSelected(MyObject myObject, int position);
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {
        private MyObject myObject;    

        public MyViewHolder(View view) {
            super(view);
            // bind views
            view.setOnClickListener((v) -> {
                int adapterPosition = getAdapterPosition();
                if(adapterPosition >= 0) {
                    clicks.onItemSelected(myObject, adapterPosition);
                }
            });
        }

        public void bind(MyObject myObject) {
            this.myObject = myObject;
            // bind data to views
        }
    }
}

Kotlin ile aynı kod:

class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter<MyViewHolder>() {
    private var items: List<MyObject> = Collections.emptyList()

    fun updateData(items: List<MyObject>) {
        this.items = items
        notifyDataSetChanged() // TODO: use ListAdapter for diffing instead if you need animations
    }

    inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) {
        private lateinit var myObject: MyObject

        init {
            // binds views
            myView.onClick {
                val adapterPosition = getAdapterPosition()
                if(adapterPosition >= 0) {
                    itemClicks.invoke(myObject, adapterPosition)
                }
            }
        }

        fun bind(myObject: MyObject) {
            this.myObject = myObject
            // bind data to views
        }
    }
}

Şey YAPMAYIN yapmanız gerekir:

1.) dokunma olaylarını manuel olarak durdurmanız gerekmez

2.) çocuk ekleme durum değişikliği dinleyicileri ile uğraşmak gerekmez

3.) RxJava'dan PublishSubject / PublishRelay'a ihtiyacınız yok

Sadece bir tıklama dinleyici kullanın.


4

Bu konudaki yaklaşımımı görün:

İlk önce böyle bir arayüz bildirin:

/**
 * Interface used for delegating item click events in a {@link android.support.v7.widget.RecyclerView}
 * Created by Alex on 11/28/2015.
 */
  public interface OnRecyclerItemClickListener<T> {

     /**
      * Called when a click occurred inside a recyclerView item view
      * @param view that was clicked
      * @param position of the clicked view
      * @param item the concrete data that is displayed through the clicked view
      */
      void onItemClick(View view, int position, T item);
   }

Ardından adaptörü oluşturun:

public class CustomRecyclerAdapter extends RecyclerView.Adapter {      

    private class InternalClickListener implements View.OnClickListener{

      @Override
      public void onClick(View v) {
        if(mRecyclerView != null && mItemClickListener != null){
            // find the position of the item that was clicked
            int position = mRecyclerView.getChildAdapterPosition(v);
            Data data = getItem(position);
            // notify the main listener
            mItemClickListener.onItemClick(v, position, data);
        }
    }
}

private final OnRecyclerItemClickListener mItemClickListener;
private RecyclerView mRecyclerView;    
private InternalClickListener mInternalClickListener;


/**
 *
 * @param itemClickListener used to trigger an item click event
 */
public PlayerListRecyclerAdapter(OnRecyclerItemClickListener itemClickListener){        
    mItemClickListener = itemClickListener;
    mInternalClickListener = new InternalClickListener();
}

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

    v.setOnClickListener(mInternalClickListener);

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

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    // do your binding here
}

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

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);

    mRecyclerView = recyclerView;
}

@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
    super.onDetachedFromRecyclerView(recyclerView);

    mRecyclerView = null;
}

public Data getItem(int position){
    return mDataset.get(position);
}
}

Ve şimdi bunun bir parçadan nasıl entegre edileceğini görelim:

public class TestFragment extends Fragment implements OnRecyclerItemClickListener<Data>{
   private RecyclerView mRecyclerView;

   @Override
   public void onItemClick(View view, int position, Data item) {
     // do something
   }

   @Override
   public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      return inflater.inflate(R.layout.test_fragment, container, false);
   }

   @Override
   public void onViewCreated(View view, Bundle savedInstanceState) {
      mRecyclerView = view.findViewById(idOfTheRecycler);
      mRecyclerView .setAdapter(new CustomRecyclerAdapter(this));
   }

4

Öğelerin alt görünümüne onClick () eklemek isterseniz, örneğin öğedeki bir düğme, bunu kendi RecyclerView.Adapter'ınızın onCreateViewHolder () öğesinde kolayca yapabileceğinizi buldum:

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View v = LayoutInflater
                    .from(parent.getContext())
                    .inflate(R.layout.cell, null);

            Button btn = (Button) v.findViewById(R.id.btn);
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //do it
                }
            });

            return new MyViewHolder(v);
        }

bunun iyi bir yol olup olmadığını bilmiyorum, ama iyi çalışıyor. Birinin daha iyi bir fikri varsa, bana söylemekten ve cevabımı düzeltmekten çok memnunum! :)


4

POJO'ların bir listesine sahipseniz ve bağdaştırıcının dışından tıklama ile bir tane almak istiyorsanız, bunu oldukça kolay bir şekilde uygulayabilirsiniz.

Bağdaştırıcınızda, tıklama etkinlikleri için bir dinleyici ve ayarlamak için bir yöntem oluşturun:

public class MyAdapter extends RecyclerView.Adapter<SitesListAdapter.ViewHolder> {
...
private List<MyPojo> mMyPojos;
private static OnItemClickListener mOnItemClickListener;

...
public interface OnItemClickListener {
    public void onItemClick(MyPojo pojo);
}

...
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
    mOnItemClickListener = onItemClickListener;
}
...

}

ViewHolder'ınızda, onClickListener'ı uygulayın ve görünümün sunduğu POJO'yu geçici olarak depolamak için bir sınıf üyesi oluşturun, bu şekilde (bu bir örnek, bir ayarlayıcı oluşturmak daha iyi olurdu):

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    public MyPojo mCurrentPojo;
    ...
    public ViewHolder(View view) {
        super(v);
        ...
        view.setOnClickListener(this); //You could set this on part of the layout too
    }

    ...
    @Override
    public void onClick(View view) {
        if(mOnItemClickListener != null && mCurrentPojo != null){
            mOnItemClickListener.onItemClick(mCurrentPojo);
        }
    }

Bağdaştırıcınızda, ViewHolder bağlı olduğunda (veya geçerli görünümde yoksa boş POJO'yu ayarlayın):

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    final MyPojo currentPojo = mMyPojos.get(position); 
    holder.mCurrentPojo = currentPojo;
    ...

İşte bu, şimdi parçanızdan / etkinliğinizden böyle kullanabilirsiniz:

    mMyAdapter.setOnItemClickListener(new mMyAdapter.OnItemClickListener() {
        @Override
        public void onItemClick(MyPojo pojo) {
            //Do whatever you want with your pojo here
        }
    });

Interface'i bir Object yöntemi gibi uygulamaya çalışıyorsunuz. Bu işe yaramayacak
Akshay

Güncelleme: İhtiyacınız olan şeymMyAdapter.setOnItemClickListener(MyAdapter.OnItemClickListener() {});
Akshay

@Akshay Üzgünüm ama kodumun doğru olduğunu düşünüyorum. Onu denedin mi? Android'deki tüm dinleyiciler aynı prensibi izler ve arayüzü 'yeni' ile başlatmanız gerekir (ör: stackoverflow.com/questions/4709870/… )
Simon

Dinleyici statik olmamalıdır.
EpicPandaForce

4

Evet yapabilirsin

public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {

    //inflate the view 

    View view = LayoutInflator.from(parent.getContext()).inflate(R.layout.layoutID,null);

    ViewHolder holder = new ViewHolder(view);

    //here we can set onClicklistener
    view.setOnClickListener(new  View.OnClickListeener(){
        public void onClick(View v)
        {
            //action
        }
    });

return holder;

3

Burada birden fazla onclick kodunu işleyebilirsiniz ve çok verimli

    public class RVNewsAdapter extends RecyclerView.Adapter<RVNewsAdapter.FeedHolder> {

    private Context context;
    List<News> newsList;
    // Allows to remember the last item shown on screen
    private int lastPosition = -1;

    public RVNewsAdapter(List<News> newsList, Context context) {
        this.newsList = newsList;
        this.context = context;
    }

    public static class FeedHolder extends RecyclerView.ViewHolder implements OnClickListener {

        ImageView img_main;
        TextView tv_title;
        Button bt_facebook, bt_twitter, bt_share, bt_comment;


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

            img_main = (ImageView) itemView.findViewById(R.id.img_main);
            tv_title = (TextView) itemView.findViewById(R.id.tv_title);
            bt_facebook = (Button) itemView.findViewById(R.id.bt_facebook);
            bt_twitter = (Button) itemView.findViewById(R.id.bt_twitter);
            bt_share = (Button) itemView.findViewById(R.id.bt_share);
            bt_comment = (Button) itemView.findViewById(R.id.bt_comment);

            img_main.setOnClickListener(this);
            bt_facebook.setOnClickListener(this);
            bt_twitter.setOnClickListener(this);
            bt_comment.setOnClickListener(this);
            bt_share.setOnClickListener(this);

        }


        @Override
        public void onClick(View v) {

            if (v.getId() == bt_comment.getId()) {

                Toast.makeText(v.getContext(), "Comment  " , Toast.LENGTH_SHORT).show();

            } else if (v.getId() == bt_facebook.getId()) {

                Toast.makeText(v.getContext(), "Facebook  " , Toast.LENGTH_SHORT).show();

            } else if (v.getId() == bt_twitter.getId()) {

                Toast.makeText(v.getContext(), "Twitter  " , Toast.LENGTH_SHORT).show();

            } else if (v.getId() == bt_share.getId()) {

                Toast.makeText(v.getContext(), "share  " , Toast.LENGTH_SHORT).show();

            }
            else {
                Toast.makeText(v.getContext(), "ROW PRESSED = " + String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
    }

    @Override
    public FeedHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_row, parent, false);
        FeedHolder feedHolder = new FeedHolder(view);

        return feedHolder;
    }

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

        holder.tv_title.setText(newsList.get(position).getTitle());


        // Here you apply the animation when the view is bound
        setAnimation(holder.img_main, position);
    }

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


    /**
     * Here is the key method to apply the animation
     */
    private void setAnimation(View viewToAnimate, int position) {
        // If the bound view wasn't previously displayed on screen, it's animated
        if (position > lastPosition) {
            Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
            viewToAnimate.startAnimation(animation);
            lastPosition = position;
        }
    }


}

Demek istedi itemView.
Davideas

3

Yorumum değiştirildi ...

public class MyViewHolder extends RecyclerView.ViewHolder {

        private Context mContext;

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

            mContext = itemView.getContext();

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {

                    int itemPosition = getLayoutPosition();
                    Toast.makeText(mContext, "" + itemPosition, Toast.LENGTH_SHORT).show();

                }
            });
        }

1
Bu bir öneri, ancak birçok kişi olumsuz oy kullanmadıkça bu yanıtı silerseniz daha iyi olur. Bu çözüm kesinlikle yanlış, işe yarıyor ama kötü programlama. Lütfen RecyclerView için bazı blogları okuyun ve bazı Adaptör kitaplıklarını inceleyin, Github'da çok sayıda, FlexAdapter, FastAdapter ve benzeri gibi birçok geçerli var ...
Davideas

1
Cevap, uzun oy alan cevapların uzun listesinden nispeten yenidir ve sayfanın alt kısmında bu yüzden hala 0 oy vardır. Bu arada, yeni kodda kullanmalısınız getAdapterPosition().
Davideas

Sadece 2 yöntemin javaDoc'unu okumalısınız.
Davideas

3

Her şeyi doğru bir şekilde uyguladığım bunu kontrol et

RecyclerViewHolder Sınıfı

public class RecyclerViewHolder extends RecyclerView.ViewHolder  {

    //view holder is for girdview as we used in the listView
    public ImageView imageView,imageView2;
    public RecyclerViewHolder(View itemView) {
        super(itemView);
        this.imageView=(ImageView)itemView.findViewById(R.id.image);
    }

}

adaptör

public class RecyclerView_Adapter extends RecyclerView.Adapter<RecyclerViewHolder> {

    //RecyclerView will extend to recayclerview Adapter
    private ArrayList<ModelClass> arrayList;
    private Context context;
    private static RecyclerViewClickListener itemListener;
    //constructor of the RecyclerView Adapter
    RecyclerView_Adapter(Context context,ArrayList<ModelClass> arrayList,RecyclerViewClickListener itemListener){
        this.context=context;
        this.arrayList=arrayList;
        this.itemListener=itemListener;
    }

    @Override
    public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //this method will inflate the custom layout and return as viewHolder
        LayoutInflater layoutInflater=LayoutInflater.from(parent.getContext());
        ViewGroup mainGroup=(ViewGroup) layoutInflater.inflate(R.layout.single_item,parent,false);
        RecyclerViewHolder listHolder=new RecyclerViewHolder(mainGroup);

        return listHolder;
    }

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

        final ModelClass modelClass=arrayList.get(position);
        //holder
        RecyclerViewHolder mainHolder=(RecyclerViewHolder)holder;
        //convert the drawable image into bitmap
        Bitmap image= BitmapFactory.decodeResource(context.getResources(),modelClass.getImage());
        //set the image into imageView
        mainHolder.imageView.setImageBitmap(image);
        //to handle on click event when clicked on the recyclerview item and
        // get it through the RecyclerViewHolder class we have defined the views there
        mainHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //get the position of the image which is clicked
             itemListener.recyclerViewListClicked(v,position);
            }
        });

    }

    @Override
    public int getItemCount() {
        return (null!=arrayList?arrayList.size():0);
    }
}

Arayüz

public interface RecyclerViewClickListener {

    //this is method to handle the event when clicked on the image in Recyclerview
    public void recyclerViewListClicked(View v,int position);
}

//and to call this method in activity
RecyclerView_Adapter adapter=new RecyclerView_Adapter(Wallpaper.this,arrayList,this);
        recyclerView.setAdapter(adapter);
        adapter.notifyDataSetChanged();


    @Override
    public void  recyclerViewListClicked(View v,int position){

        imageView.setImageResource(wallpaperImages[position]);

    }

2

Bu benim için çalıştı:

@Override
public void onBindViewHolder(PlacesListViewAdapter.ViewHolder holder, int position) {
    ----
    ----
    ----
    // Set setOnClickListener(holder);
}


@Override
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    ----
    ----
    ----

    @Override
    public void onClick(View view) {
        // Use to get the item clicked getAdapterPosition()
    }
}

Bu iyi bir yol ayar değildir setOnClickListener(holder)de onBindViewHolder(). Çünkü onBindViewHolder (...), notify () yöntemlerinden sonra çağrılmaz. Böylece, bazı durumlarda yanlış tıklama konumu elde edebilirsiniz.
Alex Kisel

İçeride tıklama dinleyicisini oluşturmanız gerekir onCreateViewHolder.
EpicPandaForce

2

Erişim mainViewait rowLayout(cell)sizin için RecyclerViewve sizin de OnBindViewHolderyazma bu kodu:

    @Override
    public void onBindViewHolder(MyViewHolder holder, final int position) {
        Movie movie = moviesList.get(position);
        holder.mainView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                System.out.println("pos " + position);
            }
        });
    }

1

View.OnClickListener arayüzünü görünüm tutucu içinde uygulamak veya aktivitenizde arayüz oluşturmak ve arayüz uygulamak yerine .. OnClickListener uygulamasında basit olarak bu kodu kullandım.

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

2
Ve her onBind () yöntem çağrısında yeni bir OnItemClickListener nesnesi oluşturmanın iyi bir yaklaşım olduğunu mu düşünüyorsunuz?
Alexandru Circus

Aferin. Harika çalışıyor!
sam

1

benim için çalıştı. Umarım yardımcı olur. En basit yol.

İç Görünüm Tutucu

class GeneralViewHolder extends RecyclerView.ViewHolder {
    View cachedView = null;

    public GeneralViewHolder(View itemView) {
        super(itemView);
        cachedView = itemView;
    }

Inside OnBindViewHolder ()

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
            final GeneralViewHolder generalViewHolder = (GeneralViewHolder) holder;
            generalViewHolder.cachedView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, "item Clicked at "+position, Toast.LENGTH_SHORT).show();
                }
            });

Ve bana bildirin, bu çözüm hakkında sorunuz var mı?


Daha onCreateViewHolderiyi performans için onClickListener'ı ayarlamanız gerekir , ancak daha sonra konumu kullanarak getAdapterPosition()(ve karşı -1
koruyunuz

1
 main_recyclerview.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
        {
            int position=rv.getChildAdapterPosition(rv.findChildViewUnder(e.getX(),e.getY()));

            switch (position)
            {
                case 0:
                {
                    wifi(position);
                    adapter2.notifyDataSetChanged();
                }
                break;

                case 1:
                {
                    sound(position);
                    adapter2.notifyDataSetChanged();
                }
                break;

                case 2:
                {
                    bluetooth(position);
                    adapter2.notifyDataSetChanged();
                }
                break;


            }
            return true;
        }

        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e)
        {

        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

        }
    });

bunu kullanarak kesin sonuçlar alabilirsiniz ..................
dileep krishnan

Soru "RecyclerView'da neden onItemClickListener () yoktur?" NOT "RecyclerView'de onItemClickListener () nasıl uygulanır?" .
Shashanth

0

Kullanım PlaceHolderView

@Layout(R.layout.item_view_1)
public class View1{

    @View(R.id.txt)
    public TextView txt;

    @Resolve
    public void onResolved() {
        txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
    }

    @Click(R.id.btn)
    public void onClick(){
        txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
    }
}

0

Android recycler view item click olayını işlemek için bir kütüphane yazdım. Tüm öğreticiyi https://github.com/ChathuraHettiarachchi/RecycleClick adresinde bulabilirsiniz.

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
            @Override
            public void onItemClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
            }
        });

veya öğeyi uzun basmak için kullanabilirsiniz

RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemLongClickListener(new RecycleClick.OnItemLongClickListener() {
            @Override
            public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
                // YOUR CODE
                return true;
            }
        });

Efendim kütüphanenizi denedim ama maven ile ilgili sorun mu yaşıyorsunuz?
Abhijeet

0

geri dönüşüm görüntüleme animasyonu test edilmedi, diğeri normal. Bence maksimum seviyeye optimize edildi. Arayüzün başka kullanımları vardır, geçici olarak yok sayabilirsiniz.

public abstract class BaseAdapterRV<VH extends BaseViewHolder> extends RecyclerView.Adapter<VH> implements AdapterInterface {
    public final String TAG = getClass().getSimpleName();

    protected final Activity mActivity;
    protected final LayoutInflater mInflater;
    protected ItemClickInterface<?, Integer> mListener;

    public BaseAdapterRV(Activity activity) {
        mActivity = activity;
        mInflater = LayoutInflater.from(mActivity);
    }

    @Override
    public final VH onCreateViewHolder(ViewGroup parent, int viewType) {
        return onCreateViewHolder(parent, viewType, mInflater);
    }

    @Override
    public final void onBindViewHolder(VH holder, int position) {
        holder.itemView.setTag(R.id.tag_view_click, position);
        //创建点击事件
        holder.itemView.setOnClickListener(mListener);
        holder.itemView.setOnLongClickListener(mListener);
        onBindVH(holder, position);
    }


    ///////////////////////////////////////////////////////////////////////////
    // 以下是增加的方法
    ///////////////////////////////////////////////////////////////////////////

    /**
     * 注意!涉及到notifyItemInserted刷新时立即获取position可能会不正确
     * 里面也有onItemLongClick
     */
    public void setOnItemClickListener(ItemClickInterface<?, Integer> listener) {
        mListener = listener;
        notifyDataSetChanged();
    }

    @NonNull
    protected abstract VH onCreateViewHolder(ViewGroup parent, int viewType, LayoutInflater inflater);

    protected abstract void onBindVH(VH holder, int position);

}

Bu Arayüz

/**
 * OnItemClickListener的接口
 * 见子类实现{@link OnItemClickListener}{@link OnItemItemClickListener}
 */
public interface ItemClickInterface<DATA1, DATA2> extends View.OnClickListener, View.OnLongClickListener {

    void onItemClick(DATA1 data1, DATA2 data2);

    boolean onItemLongClick(DATA1 data1, DATA2 data2);
}

Bu soyut bir sınıf

public abstract class OnItemClickListener<DATA> implements ItemClickInterface<View, DATA> {
    @Override
    public void onClick(View v) {
        onItemClick(v, (DATA) v.getTag(R.id.tag_view_click));
    }

    @Override
    public boolean onLongClick(View v) {
        return onItemLongClick(v, (DATA) v.getTag(R.id.tag_view_click));
    }

    @Override
    public boolean onItemLongClick(View view, DATA data) {
        return false;
    }
}

Sadece ihtiyacın var

    mAdapter.setOnItemClickListener(new OnItemClickListener<Integer>() {
        @Override
        public void onItemClick(View view, Integer integer) {

        }

        @Override
        public boolean onItemLongClick(View view, Integer integer) {
            return true;
        }
    });

RecyclerView.ViewHolder olarak BaseViewHolder
user8944115 16:17

R.id.tag_view_click, <item type = "id" name = "tag_view_click" />
user8944115 16:17

-1

Tüm bağdaştırıcı için getTag () / setTag () ve tek tıklama dinleyicisine örnek:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    String[] mDataset = { "One", "Two", "Three" };

    private final View.OnClickListener mClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Object pos = v.getTag(R.id.TAG_POSITION);
            if(pos instanceof Integer) {
                // here is your position in the dataset that was clicked
                int position = (Integer) pos;

                ...
            }
        }
    };

    class MyViewHolder extends RecyclerView.ViewHolder {
        View mItemView;
        TextView mTextView; // as example
            ...

        MyViewHolder(View itemLayoutView){
            super(itemLayoutView);

            mItemView = itemLayoutView;
            mTextView = itemLayoutView.findViewById(R.id.my_text_view_id);
            ....
            itemLayoutView.setOnClickListener(mClickListener);
        }
    }

    // Provide a suitable constructor (depends on the kind of dataset)
    public MyAdapter(String[] myDataset) {
        mDataset = myDataset;
    }

    @Override 
    public void onBindViewHolder(final ViewHolder holder, int position) {
        // you could use getTag() here for to get previous position 
        // that used the holder and for example cancel prev async requests 
        // to load images for the old position or so.
        //
        // setTag() new position that use the holder, so then user 
        // will click on the itemView - you will be able to get 
        // the position by getTag()
        holder.mItemView.setTag(R.id.TAG_POSITION, position);

        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        holder.mTextView.setText(mDataset[position]);
    }

    @Override
    public @NonNull MyAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View item_layout = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.my_recyclerview_item_layout, parent, false);
        ....
        return new MyViewHolder(item_layout);
    }

    @Override
    public int getItemCount() {
        return mDataset.length;
    }
}

Tags.xml dosyasında TAG_POSITION olarak tanımlanır

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <item name="TAG_POSITION" type="id"/>
 </resources>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.