ทำไม RecyclerView ไม่มี onItemClickListener ()


965

ผมได้รับการสำรวจRecyclerViewและฉันรู้สึกประหลาดใจที่จะเห็นว่าไม่มีRecyclerViewonItemClickListener()

ฉันมีสองคำถาม

คำถามหลัก

ฉันต้องการที่จะรู้ว่าทำไม Google ลบออกonItemClickListener()?

มีปัญหาเรื่องประสิทธิภาพหรืออย่างอื่นหรือไม่

คำถามรอง

ฉันแก้ไขปัญหาด้วยการเขียนonClickใน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) {

    }
}

นี่โอเค / มีวิธีที่ดีกว่านี้ไหม?


31
เพื่อให้โค้ดของคุณทำงานคุณต้องเพิ่ม itemLayoutView.setOnClickListener (นี่) ในตัวสร้าง ViewHolder
whitneyland

3
คุณถามคำถามที่ดี ... นักพัฒนาหลายคนมีข้อสงสัยเหมือนกันเกี่ยวกับ RecyclerView และ ListView
venkat

17
คำถาม:ทำไม RecyclerView ไม่มี OnItemClickListner () คำตอบทั้งหมดด้านล่างยกเว้น 2:วิธีเพิ่ม onclick สำหรับ RecyclerView
Manohar Reddy

2
หวังว่าจะมีใครบางคนเอาเวลาตอบคำถามออกมาจริงๆQUESTION
Ojonugwa Jude Ochalifu

1
ฉันคิดว่าพวกเขาลบเพราะประสิทธิภาพและปัญหาหน่วยความจำขยะ แต่ดูคำตอบที่ยอมรับ .... มันจะสร้างปัญหาเดียวกัน ฉันคิดว่าคุณทำผิดพลาดโดยยอมรับมันและตอนนี้คนอื่น ๆ ก็ทำผิดเพราะคุณ :)
อเล็กซ์

คำตอบ:


1207

tl; dr 2016ใช้ RxJava และ PublishSubject เพื่อแสดง Observable สำหรับการคลิก

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

โพสต์ต้นฉบับ:

ตั้งแต่การแนะนำของListView, onItemClickListenerได้รับมีปัญหา ช่วงเวลาที่คุณมีผู้ฟังคลิกสำหรับองค์ประกอบภายในใด ๆ การเรียกกลับจะไม่ถูกเรียก แต่มันไม่ได้รับแจ้งหรือมีการบันทึกไว้อย่างดี (ถ้าเลย) ดังนั้นจึงมีความสับสนและคำถามเกี่ยวกับเรื่องนี้มากมาย

ระบุว่าRecyclerViewจะนำไปสู่ขั้นตอนต่อไปและไม่มีแนวคิดเกี่ยวกับแถว / คอลัมน์ แต่มีจำนวนเด็กที่วางไว้โดยพลการพวกเขาได้มอบหมาย onClick ให้กับแต่ละคนหรือเพื่อการใช้งานโปรแกรมเมอร์

คิดว่าRecyclerviewไม่ใช่การListViewแทนที่แบบ 1: 1 แต่เป็นองค์ประกอบที่ยืดหยุ่นมากกว่าสำหรับกรณีการใช้ที่ซับซ้อน และอย่างที่คุณพูดทางออกของคุณคือสิ่งที่ Google คาดหวังจากคุณ ตอนนี้คุณมีอะแดปเตอร์ที่สามารถมอบหมาย onClick การอินเตอร์เฟซที่ส่งผ่านคอนสตรัคซึ่งเป็นรูปแบบที่ถูกต้องสำหรับทั้งสองและListViewRecyclerview

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

}

แล้วในอะแดปเตอร์ของคุณ

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

ตอนนี้ดูที่รหัสชิ้นสุดท้าย: onCreateViewHolder(ViewGroup parent, int viewType)ลายเซ็นแนะนำประเภทการดูที่แตกต่างกันแล้ว สำหรับหนึ่งในนั้นคุณจะต้องมีผู้ดูที่แตกต่างเช่นกันและในภายหลังแต่ละคนจะมีชุดคลิกที่แตกต่างกัน หรือคุณสามารถสร้างผู้ดูทั่วไปที่ใช้มุมมองและมุมมองใดก็ได้onClickListenerและใช้ตามนั้น หรือมอบหมายให้ผู้ควบคุมออเดอร์เอเตอร์หนึ่งระดับเพื่อให้แฟรกเมนต์ / กิจกรรมหลายรายการมีรายการเดียวกันกับพฤติกรรมการคลิกที่แตกต่างกัน อีกครั้งความยืดหยุ่นทั้งหมดอยู่ข้างคุณ

มันเป็นองค์ประกอบที่จำเป็นจริงๆและใกล้เคียงกับการใช้งานและการปรับปรุงภายในของเราListViewจนถึงปัจจุบัน เป็นเรื่องดีที่ Google ยอมรับในที่สุด


78
RecyclerView.ViewHolder มีเมธอด getPosition () ด้วยการปรับเปลี่ยนรหัสนี้คุณสามารถส่งตำแหน่งไปยังผู้ฟังได้
se_bastiaan

13
เขาพลาดอย่างสมบูรณ์onBindViewHolder(holder, position)ซึ่งเป็นที่ที่ข้อมูลควรจะถูกเติม
MLProgrammer-CiM

26
@se_bastiaan getPosition()เลิกใช้แล้ว "วิธีนี้เลิกใช้เนื่องจากความหมายคลุมเครือเนื่องจากการจัดการ async * ของการอัปเดตอะแดปเตอร์โปรดใช้ {@link #getLayoutPosition ()} หรือ * {@link #getAdapterPosition () "
upenpat

8
คุณมีหลายทางเลือก การวางตำแหน่งลงในฟิลด์ int ภายในผู้ดูอัปเดตขณะที่มีผลผูกพันแล้วส่งคืนเมื่อคลิกเป็นหนึ่ง
MLProgrammer-CiM

8
@ MLProgrammer-CiM "คุณมีหลายตัวเลือกการวางตำแหน่งลงในช่องข้อมูลภายในช่องมองภาพให้อัปเดตขณะที่เชื่อมโยงจากนั้นส่งคืนเมื่อคลิกเป็นหนึ่ง" ViewHolder มีค่านี้อยู่แล้วและตั้งค่าไว้แล้ว เพียงแค่โทรviewHolder.getPosition();
Chad Bingham

104

ทำไม RecyclerView จึงไม่มี onItemClickListener

RecyclerViewเป็นกล่องเครื่องมือในทางตรงกันข้ามของเดิมListViewก็มีการสร้างน้อยกว่าในคุณสมบัติและความยืดหยุ่นมากขึ้น onItemClickListenerไม่ได้เป็นคุณลักษณะเฉพาะถูกลบออกจาก ListView แต่มีผู้ฟังจำนวนมากและวิธีการที่จะขยายไปยังความชอบของคุณมันมีพลังมากขึ้นในมือขวา;)

ในความคิดของคุณลักษณะที่ซับซ้อนมากที่สุดในการลบออกRecyclerViewเป็นจานด่วนเลื่อน คุณสมบัติอื่น ๆ ส่วนใหญ่สามารถนำมาใช้ใหม่ได้อย่างง่ายดาย

ถ้าคุณต้องการที่จะรู้ว่าสิ่งดีๆอื่น ๆ คุณสมบัติRecyclerViewเพิ่มอ่านนี้คำตอบของคำถามอื่น

หน่วยความจำมีประสิทธิภาพ - โซลูชันดร็อปอินสำหรับ onItemClickListener

โซลูชันนี้ได้รับการเสนอโดยHugo Visserซึ่งเป็น Android GDE หลังจากRecyclerViewได้รับการปล่อยตัว เขาสร้างคลาสที่ไม่มีลิขสิทธิ์ให้คุณเพียงวางรหัสและใช้งาน

มันแสดงบางส่วนของความเก่งกาจที่นำมาด้วยโดยการใช้RecyclerViewRecyclerView.OnChildAttachStateChangeListener

แก้ไข 2019 : รุ่น kotlin โดยฉันหนึ่ง java จาก Hugo Visser ด้านล่าง

Kotlin / Java

สร้างไฟล์values/ids.xmlและวางไว้ในมัน:

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

จากนั้นเพิ่มรหัสด้านล่างลงในแหล่งที่มาของคุณ

Kotlin

การใช้งาน:

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

(นอกจากนี้ยังรองรับการคลิกไอเท็มแบบยาวและดูด้านล่างสำหรับคุณลักษณะอื่นที่ฉันได้เพิ่มไว้)

การใช้งาน (การปรับตัวของฉันกับรหัส Java Hugo Visser):

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

(ดูด้านล่างคุณต้องเพิ่มไฟล์ XML)

คุณสมบัติโบนัสของ Kotlin version

บางครั้งคุณไม่ต้องการให้รายการทั้งหมดของ RecyclerView สามารถคลิกได้

เพื่อจัดการเรื่องนี้ฉันได้แนะนำItemClickSupportViewHolderอินเทอร์เฟซที่คุณสามารถใช้ในViewHolderการควบคุมรายการที่สามารถคลิกได้

ตัวอย่าง:

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

ชวา

การใช้งาน:

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

(นอกจากนี้ยังสนับสนุนการคลิกรายการยาว)

การใช้งาน (ความคิดเห็นที่เพิ่มโดยฉัน):

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

มันทำงานอย่างไร (ทำไมมันถึงมีประสิทธิภาพ)

ชั้นนี้ทำงานโดยการแนบไปRecyclerView.OnChildAttachStateChangeListener ฟังนี้จะได้รับแจ้งทุกครั้งที่เด็กถูกแนบมาหรือออกจากRecyclerView RecyclerViewรหัสนี้ใช้เพื่อต่อท้ายฟังแตะ / ยาวคลิกเพื่อดู ผู้ฟังนั้นถามถึงRecyclerViewสิ่งRecyclerView.ViewHolderที่บรรจุตำแหน่ง

นี่เป็นวิธีที่มีประสิทธิภาพมากกว่าแล้วเพราะมันหลีกเลี่ยงการสร้างผู้ฟังหลายคนสำหรับแต่ละมุมมองและทำลายและสร้างมันต่อไปในขณะที่RecyclerViewเลื่อนอยู่

คุณสามารถปรับรหัสเพื่อให้ผู้ถือกลับคืนได้เองหากคุณต้องการมากกว่านี้

คำพูดสุดท้าย

โปรดทราบว่ามันเป็นเรื่องปกติที่จะจัดการกับมันในอะแดปเตอร์ของคุณโดยการตั้งค่าในแต่ละมุมมองของรายการของคุณให้เป็น listener การคลิกเช่นเดียวกับคำตอบอื่น ๆ ที่เสนอ

ไม่ใช่สิ่งที่มีประสิทธิภาพที่สุดในการทำ (คุณสร้างผู้ฟังใหม่ทุกครั้งที่คุณใช้มุมมองใหม่) แต่ก็ใช้งานได้และในกรณีส่วนใหญ่มันไม่ใช่ปัญหา

นอกจากนี้ยังเป็นเรื่องเล็กน้อยที่จะแยกแยะความกังวลเพราะงานของอะแดปเตอร์ไม่ใช่ตัวแทนการคลิกเหตุการณ์


addOnChildAttachStateChangeListener ใน Constructor และไม่เคยลบมันออก?
สะบ้า

@Saba คุณไม่ควรที่จะใช้สร้างโดยตรง แต่ผ่านวิธีการคงและaddTo() removeFrom()อินสแตนซ์เกี่ยวข้องกับแท็ก recyclerview และตายไปด้วยหรือเมื่อถูกลบด้วยตนเอง
Daniele Segato

รหัสมากเมื่อสิ่งที่คุณต้องทำคือการตั้งฟังบนคลิกonCreateViewHolderและนั่นคือมัน
EpicPandaForce

ข้อโต้แย้งของคุณลื่นไหลไม่เกี่ยวกับปริมาณของรหัส แต่หลักการประสิทธิภาพและความรับผิดชอบและปริมาณของรหัสไม่ใช่ตัวบ่งชี้ที่ดีของการแก้ปัญหาที่ดี / ไม่ดีโดยเฉพาะอย่างยิ่งเมื่อรหัสนั้นสามารถนำมาใช้ใหม่และมีประสิทธิภาพ เมื่อคุณได้ใส่รหัสในโครงการของคุณ (ซึ่งคุณสามารถพิจารณาเป็นห้องสมุดรวม) ทั้งหมดที่คุณต้องเป็นซับ 1 RecyclerViewบน
Daniele Segato

@DanieleSegato ขอบคุณมากสำหรับสิ่งนี้!
Mr. Octodood

90

ฉันชอบวิธีนี้และฉันใช้มัน

ภายใน

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

ใส่

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

และสร้างคลาสนี้ได้ทุกที่ที่คุณต้องการ

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

ฉันเคยอ่านมาก่อนว่ามีวิธีที่ดีกว่า แต่ฉันชอบวิธีนี้ง่ายและไม่ซับซ้อน


23
น่าจะMyOnClickListenerเป็นตัวแปรอินสแตนซ์เนื่องจากคุณจะสร้างอินสแตนซ์ใหม่ทุกครั้งด้วยnewคำหลัก
user2968401

14
recyclerView.getChildPosition (V); ตอนนี้ใช้ depycated อีกครั้ง indexOfChild (V);
Qadir Hussain

4
คุณไม่มีปัญหาเมื่อเลื่อน? ในการทดสอบของฉัน itemPosition ดูเหมือนว่าจะขึ้นอยู่กับการรีไซเคิลมุมมองดังนั้นจึงผิดพลาดเมื่อเทียบกับรายการทั้งหมดของฉันในอะแดปเตอร์
Simon

16
วิธีรับrecyclerViewใน MyOnClickListener
guo

3
แทนที่จะใช้: int itemPosition = recyclerView.indexOfChild (v); คุณควรใช้: RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder (v); int itemPosition = holder.getAdapterPosition ();
Gordon Freeman

35

Android Recyclerview ด้วยonItemClickListenerทำไมเราไม่ลองนี่ใช้งานได้ListViewแค่เท่านั้น

ที่มา: ลิงค์

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

  }
}

และตั้งเป็น RecyclerView:

    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
ไม่มีความสง่างามที่จะซื่อสัตย์
vishal dharankar

@vishaldharankar ทำไมไม่ ฉันคิดว่ามันเป็นวิธีที่ดีที่สุดในการหลีกเลี่ยงความขัดแย้งของการเปลี่ยนโฟกัสหลังจากใช้งานSwipeRefreshLayout
NickUnuchek

สิ่งนี้ไม่จำเป็นทั้งหมดคุณสามารถใช้ ViewOnClickListener แทนการดักจับการสัมผัส
EpicPandaForce

23

ขอบคุณ @marmor ฉันได้อัปเดตคำตอบของฉัน

ฉันคิดว่ามันเป็นวิธีแก้ปัญหาที่ดีในการจัดการ onClick () ในConstructorคลาสViewHolderและส่งต่อไปยังคลาสพาเรนต์ผ่านทางอินเตอร์เฟสOnItemClickListener

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

การใช้งานอะแดปเตอร์ในคลาสอื่น:

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
สิ่งนี้จะสร้างและรวบรวมขยะจำนวนมากของวัตถุเมื่อเลื่อนคุณควรสร้าง OnClickListener หนึ่งอันและใช้ใหม่อีกครั้ง
marmor

2
นอกจากนี้ยังonBindViewHolder()เรียกว่าหลายครั้งสำหรับมุมมองเดียวกันเมื่อเลื่อน แม้แต่การสร้างซิงเกิลOnClickListenerก็ไม่ได้ช่วยอะไรเพราะคุณจะทำการรีเซ็ตOnClickListenerทุกครั้งที่onBindViewHolder()มีการโทรออก ดูโซลูชันของ @ MLProgrammer-CiM แทน
vovahost

คุณยังสามารถปรับปรุง @ MLProgrammer-CiM และแทนที่จะสร้างวัตถุผู้ฟังสำหรับทุกมุมมองในบรรทัดนี้MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() ....คุณสามารถสร้างผู้ฟังเพียงคนเดียวสำหรับทุกมุมมอง
vovahost

21

พวกใช้รหัสนี้ในกิจกรรมหลักของคุณ วิธีการที่มีประสิทธิภาพมาก

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

นี่คือคลาสอะแดปเตอร์ของคุณ

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

หลังจากนี้คุณจะได้รับวิธีการแทนที่นี้ในกิจกรรมของคุณ

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

5
ฉันสงสัยว่าผู้ใช้เลื่อนขึ้นและลง OnClickListener จะสร้าง & รีไซเคิลซ้ำแล้วซ้ำอีกหรือไม่มันมีประสิทธิภาพหรือไม่
Vinh.TV

เพื่อให้ได้ตำแหน่งที่อัปเดตของการ์ดสิ่งเล็ก ๆ น้อย ๆ นี้อาจถูกบุกรุก
waqas ali

สวัสดีเพื่อนที่ดีมีเสน่ห์ในการทำงานฉันมีความต้องการกิจกรรมกับหมวดหมู่และผลิตภัณฑ์ในตอนแรกถ้าผู้ใช้เลือกไอคอนหมวดหมู่ฉันต้องการที่จะแสดงหมวดหมู่ในกล่องโต้ตอบหรือกิจกรรมถ้าผู้ใช้เลือกหมวดหมู่ใด ๆ ตามที่โหลดโหลดข้อมูลที่กรองกิจกรรมแรก วิธีแก้ปัญหา
Harsha

วันที่ 1: คุณต้องเพิ่มวิธีการชื่อ OnProductClicked ในอินเทอร์เฟซ OnCardClickListner เช่นอินเทอร์เฟซสาธารณะนี้ OnCardClickListner {void OnCardClicked (ดูมุมมองตำแหน่ง int); เป็นโมฆะ OnProductClicked (ดูมุมมองตำแหน่ง int); } 2nd: จากนั้นใช้ฟังคลิกที่ไอคอนผลิตภัณฑ์ของคุณเช่นนี้ holder.yourProductIcon.setOnClickListener (ใหม่ ViewOnClickListener () {@Override โมฆะสาธารณะ onClick (ดู v) {onCardClickListnerOnProductClicked (v, ตำแหน่ง);}});
waqas ali

ฉันไม่สามารถแทนที่ OnCardClicked ผู้คนกำลังตอบโต้คำตอบนี้อย่างไร
The_Martian

19

> RecyclerView แตกต่างจาก Listview อย่างไร

สิ่งหนึ่งที่แตกต่างคือมีLayoutManagerคลาสพร้อม RecyclerView ซึ่งคุณสามารถจัดการสิ่งที่คุณชอบRecyclerView-

เลื่อนแนวนอนหรือแนวตั้งโดยLinearLayoutManager

GridLayout โดย GridLayoutManager

GridLayout ที่เซ StaggeredGridLayoutManager

ชอบการเลื่อนแนวนอนสำหรับ RecyclerView-

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

15

การติดตามโซลูชัน RxJava ที่ยอดเยี่ยมของ MLProgrammer-CiM

กิน / สังเกตการคลิก

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

แก้ไขtlต้นฉบับdrเป็น:

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

PublishSubject#asObservable()ถูกลบออก. เพียงแค่กลับซึ่งเป็นPublishSubjectObservable


คุณได้รับ mClickConsumer ในบรรทัดที่สองอยู่ที่ไหนถ้าคุณช่วยอธิบายหน่อย . rxAdapter.getPositionClicks () สมัคร (mClickConsumer);
bluetoothfx

14

วิธีนำตัวอย่างทั้งหมดมารวมกัน ...

  • การจัดการ onClick ()
  • เคอร์เซอร์ - RecyclerView
  • ประเภท ViewHolder

    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ก็เป็นไปได้เพียงทำ:

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นี่คือรหัสของฉัน:

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

ระวังว่าgetAdapterPositionสามารถส่งคืน-1สำหรับ "ไม่มีตำแหน่ง"
EpicPandaForce

9

ฉันทำแบบนี้ง่ายมาก:

เพียงเพิ่ม1 บรรทัดสำหรับตำแหน่ง RecyclerView ที่ถูกคลิก :

int position = getLayoutPosition()

รหัสแบบเต็มสำหรับคลาสViewHolder :

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

หวังว่านี่จะช่วยคุณได้


คุณควรใช้แทนgetAdapterPosition รักษาการณ์getLayoutPosition -1
EpicPandaForce

7

ฉันใช้วิธีนี้เพื่อเริ่มเจตนาจาก RecyclerView:

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

มันไม่ใช่วิธีที่ดี เพราะonBindViewHolder(...)ไม่ได้ถูกเรียกหลังจากnotify()วิธีการ ดังนั้นคุณสามารถคลิกผิดตำแหน่งได้ในบางสถานการณ์
Alex Kisel

5

RecyclerView ไม่มีonItemClickListenerเนื่องจาก RecyclerView รับผิดชอบการรีไซเคิลมุมมอง (แปลกใจ!) ดังนั้นจึงเป็นความรับผิดชอบของมุมมองที่ถูกรีไซเคิลเพื่อจัดการกับกิจกรรมการคลิกที่ได้รับ

สิ่งนี้ทำให้ใช้งานได้ง่ายขึ้นโดยเฉพาะอย่างยิ่งหากคุณมีรายการที่สามารถคลิกได้หลายแห่ง


อย่างไรก็ตามการตรวจสอบการคลิกที่รายการ RecyclerView นั้นง่ายมาก สิ่งที่คุณต้องทำคือกำหนดอินเทอร์เฟซ (ถ้าคุณไม่ได้ใช้ Kotlin ซึ่งในกรณีนี้คุณเพิ่งผ่านแลมบ์ดา):

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:

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

สิ่งที่คุณไม่จำเป็นต้องทำ:

1. ) คุณไม่จำเป็นต้องสกัดกั้นเหตุการณ์การสัมผัสด้วยตนเอง

2. ) คุณไม่จำเป็นต้องยุ่งกับเด็ก ๆ แนบผู้ฟังการเปลี่ยนแปลงสถานะ

3. ) คุณไม่ต้องการ PublishSubject / PublishRelay จาก RxJava

เพียงใช้ฟังคลิก


4

ดูแนวทางของฉันเกี่ยวกับเรื่องนี้:

ก่อนอื่นให้ประกาศส่วนต่อประสานดังนี้:

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

จากนั้นสร้างอะแดปเตอร์:

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

และตอนนี้เรามาดูวิธีการรวมสิ่งนี้จากชิ้นส่วน:

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

หากคุณต้องการเพิ่ม onClick () ลงในมุมมองลูกของไอเท็มตัวอย่างเช่นปุ่มในไอเท็มฉันพบว่าคุณสามารถทำได้อย่างง่ายดายใน onCreateViewHolder () ของ RecyclerView ของคุณเองเช่นนี้:

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

ฉันไม่รู้ว่ามันเป็นวิธีที่ดี แต่ใช้งานได้ดี หากใครมีความคิดที่ดีกว่าดีใจมากที่บอกฉันและแก้ไขคำตอบของฉัน! :)


4

นี่เป็นวิธีการใช้งานได้ง่ายมากหากคุณมีรายการ POJO และต้องการดึงข้อมูลหนึ่งคลิกจากภายนอกอะแดปเตอร์

ในอะแดปเตอร์ของคุณสร้างฟังสำหรับเหตุการณ์คลิกและวิธีการตั้ง:

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 ของคุณให้ใช้ onClickListener และสร้างสมาชิกคลาสเพื่อเก็บ POJO ไว้ชั่วคราวมุมมองที่นำเสนอด้วยวิธีนี้ (นี่คือตัวอย่างการสร้าง setter น่าจะดีกว่า):

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

กลับไปที่อะแดปเตอร์ของคุณตั้ง POJO ปัจจุบันเมื่อ ViewHolder ถูกผูกไว้ (หรือเป็นโมฆะถ้ามุมมองปัจจุบันไม่มีหนึ่ง):

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

เพียงเท่านี้คุณสามารถใช้มันได้จากส่วน / กิจกรรมของคุณ:

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

คุณกำลังพยายามที่จะใช้ส่วนต่อประสานราวกับว่ามันจะเป็นวิธีการของวัตถุ สิ่งนี้จะไม่ทำงาน
Akshay

อัปเดต: สิ่งที่คุณต้องการคือmMyAdapter.setOnItemClickListener(MyAdapter.OnItemClickListener() {});
Akshay

@ Akshay ขออภัย แต่ฉันคิดว่ารหัสของฉันถูกต้อง คุณลองหรือยัง ผู้ฟังทั้งหมดบน Android เป็นไปตามหลักการเดียวกันและคุณต้องสร้างอินเทอร์เฟซด้วย 'ใหม่' (เช่น: stackoverflow.com/questions/4709870/… )
Simon

ผู้ฟังไม่ควรคงที่
EpicPandaForce

4

ใช่คุณสามารถ

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

ที่นี่คุณสามารถจัดการกับรหัส onclick ดูด้านล่างและมีประสิทธิภาพมาก

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


}

itemViewเขาหมายถึง
Davideas

3

แก้ไขความคิดเห็นของฉัน ...

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
มันเป็นข้อเสนอแนะ แต่ดีกว่าถ้าคุณลบคำตอบนี้เว้นแต่ว่าคนจำนวนมากจะลงคะแนนในเชิงลบ วิธีการแก้ปัญหานี้ผิดอย่างแน่นอนมันทำงาน แต่การเขียนโปรแกรมไม่ดี โปรดอ่านบล็อกบางส่วนสำหรับ RecyclerView และศึกษาไลบรารีตัวแปลงบางตัวมีหลายตัวที่ถูกต้องใน Github อยู่แล้วเช่น FlexibleAdapter, FastAdapter และอื่น ๆ ...
Davideas

1
คำตอบของคุณค่อนข้างใหม่สำหรับรายการคำตอบที่ได้รับการโหวตอย่างยาวและที่ด้านล่างของหน้านั่นคือเหตุผลว่าทำไมมันยังมี 0 คะแนน getAdapterPosition()โดยวิธีการในรหัสใหม่คุณควรใช้
Davideas

คุณเพียงแค่ต้องอ่าน javaDoc ของ 2 วิธี
Davideas

3

เลือกอันนี้ที่ฉันได้นำไปใช้ทุกสิ่งด้วยวิธีที่เหมาะสม

RecyclerViewHolder Class

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

}

อะแดปเตอร์

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

อินเตอร์เฟซ

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

สิ่งนี้ใช้ได้กับฉัน:

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

มันไม่ได้เป็นวิธีที่ดีในการตั้งค่าในsetOnClickListener(holder) onBindViewHolder()เนื่องจาก onBindViewHolder (... ) ไม่ได้ถูกเรียกใช้หลังจากวิธีการแจ้งเตือน () ดังนั้นคุณสามารถคลิกผิดตำแหน่งได้ในบางสถานการณ์
Alex Kisel

onCreateViewHolderคุณควรสร้างภายในคลิกฟัง
EpicPandaForce

2

เข้าถึงmainViewของrowLayout(cell)ให้กับคุณRecyclerViewและในการOnBindViewHolderเขียนรหัสนี้:

    @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

แทนที่จะใช้อินเตอร์เฟส ViewOnClickListener ภายในตัวยึดมุมมองหรือการสร้างและอินเทอร์เฟซและการใช้อินเตอร์เฟสในกิจกรรมของคุณ .. ฉันใช้รหัสนี้เพื่อง่ายในการปรับใช้ OnClickListener

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
และคุณคิดว่าการสร้างวัตถุ OnItemClickListener ใหม่ที่การเรียกใช้เมธอด onBind () แต่ละครั้งเป็นวิธีการที่ดีใช่ไหม
Alexandru Circus

ทำได้ดีมาก ใช้งานได้ดี!
sam

1

มันใช้งานได้สำหรับฉัน หวังว่ามันจะช่วย วิธีที่ง่ายที่สุด

มุมมองด้านใน

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

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

ภายใน 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();
                }
            });

และแจ้งให้เราทราบคุณมีคำถามเกี่ยวกับวิธีแก้ปัญหานี้หรือไม่?


คุณควรตั้ง onClickListener onCreateViewHolderเพื่อประสิทธิภาพที่ดีขึ้น แต่คุณต้องรับตำแหน่งโดยใช้getAdapterPosition()(และป้องกัน-1)
EpicPandaForce

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

        }
    });

การใช้ u คุณสามารถรับผลลัพธ์ที่แน่นอน ..................
dileep krishnan

คำถามคือ"ทำไม RecyclerView ไม่มี onItemClickListener ()?" ไม่ใช่ "วิธีการใช้ onItemClickListener () ใน RecyclerView?" .
Shashanth

0

ใช้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 คลิกมุมมองรายการรีไซเลอร์เหตุการณ์ คุณสามารถดูบทแนะนำทั้งหมดได้ที่https://github.com/ChathuraHettiarachchi/RecycleClick

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

หรือเพื่อจัดการรายการกดแบบยาวที่คุณสามารถใช้ได้

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

คุณฉันลองใช้ห้องสมุดของคุณแล้ว แต่กำลังเผชิญปัญหากับ maven หรือไม่?
Abhijeet

0

ยังไม่ได้ทดสอบภาพเคลื่อนไหว recyclerview ส่วนอีกเรื่องเป็นเรื่องปกติ ฉันคิดว่ามันได้รับการปรับปรุงให้มีประสิทธิภาพสูงสุด อินเทอร์เฟซมีการใช้งานอื่น ๆ คุณสามารถละเว้นชั่วคราว

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

}

นี่คือส่วนต่อประสาน

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

นี่เป็นคลาสนามธรรม

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

คุณต้องการมันเท่านั้น

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

        }

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

BaseViewHolder ในฐานะ RecyclerView.ViewHolder
user8944115

R.id.tag_view_click ต้องการให้คุณประกาศในไดเรกทอรีค่า <item type = "id" name = "tag_view_click" />
user8944115

-1

ตัวอย่างกับ getTag () / setTag () และฟังคลิกเดียวสำหรับอะแดปเตอร์ทั้งหมด:

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

TAG_POSITION กำหนดไว้ในไฟล์ tags.xml เป็น

 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <item name="TAG_POSITION" type="id"/>
 </resources>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.