RecyclerView onClick


583

มีใครใช้วิธีRecyclerViewพบการตั้งค่าonClickListenerรายการในRecyclerView? ฉันคิดว่าการตั้งค่าผู้ฟังให้กับแต่ละเลย์เอาท์ของแต่ละรายการ แต่ดูเหมือนจะยุ่งยากมากเกินไปฉันแน่ใจว่ามีวิธีที่RecyclerViewจะฟังonClickเหตุการณ์ แต่ฉันคิดไม่ออกเลย



4
RecyclerViewDemoฉันพบว่าโครงการนี้ยอดเยี่ยมโดยใช้อินเทอร์เฟซเพื่อให้การดำเนินการฟรีมากขึ้น
— MewX

2
ตรวจสอบบทช่วย
— Bikesh M

ง่ายและใช้งานง่าย - github.com/rahulkapoor1/ClickableAdapter
— Rahul

stackoverflow.com/a/31199564/5788247
— Shomu

คำตอบ:


477

เนื่องจาก API มีการเปลี่ยนแปลงอย่างรุนแรงมันจะไม่แปลกใจถ้าคุณจะสร้างOnClickListenerสำหรับแต่ละรายการ มันไม่ได้เป็นเรื่องยุ่งยากมากนัก ในการดำเนินการของRecyclerView.Adapter<MyViewHolder>คุณคุณควรจะมี:

private final OnClickListener mOnClickListener = new MyOnClickListener();

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

onClickวิธีการ:

@Override
public void onClick(final View view) {
    int itemPosition = mRecyclerView.getChildLayoutPosition(view);
    String item = mList.get(itemPosition);
    Toast.makeText(mContext, item, Toast.LENGTH_LONG).show();
}

32
จะทำอย่างไรถ้าฉันต้องการลบแถวในการคลิก
— Piyush Kukadiya

20
ฉันชอบคำตอบนี้ดีกว่าคำที่คุณเชื่อมโยง ใครต้องการที่จะเขียนฟังท่าทางและการตรวจสอบกล่องกดเพื่อจัดการกับสิ่งนี้ Google--
— Lo-Tan

17
getChildPosition (มุมมอง) เลิกใช้วิธี
— Jigar

45
คุณรังเกียจที่จะบอกว่าคลาสของคุณคืออะไร onClick()เป็นของOnClickListenerสามารถแนบไปกับมุมมองใดก็ได้ คำถามทั้งหมดที่นี่คือที่! โปรดใช้ความพยายามไม่เพียง แต่จะระบุชื่อด้วยวิธีการเท่านั้น แต่อย่างน้อยต้องมีชั้นเรียนด้วย หากคุณไม่ได้บอกว่ารหัสของคุณจะถูกเพิ่มลงในอะแดปเตอร์คำตอบของคุณไม่ได้ช่วยจริงๆ
— Vince

16
เมธอด onClick ควรอยู่ในแฟรกเมนต์ที่มี RecyclerView หรือไม่ เนื่องจากคุณอ้างอิง mRecyclerView ในคลาส MyOnClickListener ของคุณ คุณได้รับการอ้างอิงไปยังวัตถุนั้นอยู่ที่ไหน
— Ced

606

นี่คืองานที่ดีและน้อยทางคู่แน่นที่จะใช้สำหรับ OnClickListenerRecyclerView

ตัวอย่างการใช้งาน:

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

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

RecyclerItemClickListener การดำเนินงาน:

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


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

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

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

  GestureDetector mGestureDetector;

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

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

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

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

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

85
สิ่งนี้จะไม่ให้เบาะแสเกี่ยวกับการคลิกปุ่มหรือมุมมอง (ภายในรายการ) ใด ๆ แต่สำหรับการคลิกไอเท็มโดยรวมก็ถือว่าใช้ได้
— Niranjan

27
ความคิดเห็นของ ngen นั้นถูกต้อง - หากคุณต้องการแนบผู้ฟัง onClick กับรายการเฉพาะภายในมุมมองรายการคุณอาจทำเช่นนั้นในอะแดปเตอร์ของคุณใน onBindViewHolder หรือในมุมมองของคุณเอง
— Jacob Tabak

16
ปัญหาอย่างหนึ่งของวิธีนี้คือเมื่อคุณกำลังทำบางสิ่งที่ใช้เวลาไม่กี่ร้อยมิลลิวินาทีเช่นเริ่มกิจกรรม เมื่อรายการถูกคลิกและมีภาพเคลื่อนไหวที่ถูกคลิกจะมีความล่าช้าที่เห็นได้ชัดเจนระหว่างการคลิกและการดูภาพเคลื่อนไหว
— Gak2

20
วิธีแก้ปัญหานี้ให้ความรู้สึกอึดอัดใจมากมีความล่าช้าในการประมวลผล 'คลิก' และความรู้สึกไม่ได้เป็นเพียงแค่นั้น
— wasyl

6
ใครช่วยอธิบายให้ฉันฟังได้ว่าทำไมการแก้ปัญหาด้วย GestureDetector นี้ควรเป็นวิธีแก้ปัญหาที่ดีกว่าการใช้ "setOnClickListener" ด้านในของ onBindViewHolder () ในอะแดปเตอร์ตามองค์ประกอบหรือไม่ อย่างน้อยฉันต้องการรหัสน้อยกว่าด้วยโซลูชัน GestureDetector ขอบคุณสำหรับคำอธิบาย
— e-nature

115

ฉันทำอย่างนี้โดยไม่ต้องเรียนเกินควรตรวจจับ ฯลฯ รหัสง่าย ๆ ในอะแดปเตอร์ของเรา ทางออกที่ดีโดยเฉพาะอย่างยิ่งสำหรับ longClick นำเสนอก่อนหน้านี้

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

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

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

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

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

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

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

จากนั้นในส่วนหรือกิจกรรมเพียงแค่กด:

PasswordAdapter mAdapter = ...;

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

    @Override
    public void onItemLongClick(int position, View v) {
        Log.d(TAG, "onItemLongClick pos = " + position);
    }
});

แทน OurAdapter.clickListener ฉันคิดว่า Marurban หมายถึง PasswordAdapter.clickListener และแทนที่จะเป็น TrainingAdapter.ClickListener () ควรเป็น PasswordAdapter.ClickListener () นอกเหนือจากนั้นทางออกที่ดี Marurban! ทำงานให้ฉัน
— เสนอชื่อ

ผู้ฟัง onItemClick กำลังเปิดใช้งานเมื่อคลิกแบบยาว
— Rashad.Z

10
ViewHolder ต้องเป็นแบบคงที่เพื่อประสิทธิภาพที่ดีที่สุด นี่ไม่ใช่คำตอบที่ดี
— Gilberto Ibarra

10
clickListener แบบคงที่สร้างหน่วยความจำรั่ว ประกาศให้ฟังเป็นแบบไม่คงที่และผูกไว้กับ ViewHolder แทน
— BladeCoder

1
@AJW วิธีที่ง่ายที่สุดคือการเริ่มต้นฟังก่อนและส่งผ่านมันเป็นอาร์กิวเมนต์ไปยังตัวสร้างอะแดปเตอร์แล้วตัวสร้าง ViewHolder
— BladeCoder

97

ตรวจสอบที่คล้ายกันคำถาม @ CommonsWare ของความคิดเห็นลิงก์ไปนี้ซึ่งจะใช้งานอินเตอร์เฟซในOnClickListenerviewHolder

นี่คือตัวอย่างง่ายๆของViewHolder:

    TextView textView;//declare global with in adapter class

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

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

      }

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

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

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

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

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

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

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

        }

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

        }


      }
  }

Adapterแล้วมีลักษณะเช่นนี้

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

        return new ViewHolder(view);
    }

14
สิ่งนี้ดูเหมือนจะไปในทิศทางที่ผิด หากคุณต้องการใช้ recyclerview อีกครั้งในแฟรกเมนต์ / กิจกรรมอื่นอะแด็ปเตอร์ / ผู้ดูจะกำหนดตรรกะของการคลิกแทนที่จะเป็นสิ่งที่มีอยู่ การคลิกควรได้รับการจัดการโดยตรงหรือโดยอ้อมด้วยอินสแตนซ์ที่มีอยู่ ดูเหมือนว่าผู้ฟังแบบสัมผัสเป็นวิธีเดียวที่มีประสิทธิภาพในการดำเนินเรื่องนี้
— ian.shaun.thomas

18
@tencent ฉันไม่เห็นว่าเป็นปัญหา หาก ViewHolder นั้นมีข้อมูลทั้งหมดเกี่ยวกับข้อมูลที่ถูกเลือกเมื่อองค์ประกอบนั้นถูกคลิกดังนั้นความรับผิดชอบเพียงอย่างเดียวของคอนเทนเนอร์คือการแสดงองค์ประกอบ N ไม่ใช่การจัดการเลือกองค์ประกอบ i-th ที่เฉพาะเจาะจงออกไป ขององค์ประกอบ N ListViewอยู่แล้วมีปัญหาถ้าคุณมีการสร้างรายการของวัตถุที่มีความซับซ้อนมากขึ้นกว่าเพียงแถวที่เรียบง่าย ถ้าคุณต้องการจัดการเหตุการณ์ต่าง ๆ ขึ้นอยู่กับว่าคุณคลิกที่รายการใดใน ListView คุณเมาแล้ว ที่นี่คุณมีผู้ฟังแต่ละคน
— EpicPandaForce

2
ฉันเห็นด้วยกับ @EpicPandaForce ในอันนี้ ฉันมาเพื่อกำจัดคำตอบนี้หลังจากอ่านส่วนของหนังสือ Commonsware เกี่ยวกับการจัดการคลิกใน RecyclerViews มันใช้งานได้ดีมากสำหรับฉันจนถึงตอนนี้
— AdamMc331

1
findViewById ถูกนำมาใช้เฉพาะในการสร้างตัวยึดมุมมองที่นี่ (ดังนั้น onCreateViewHolder) ตัวยึดมุมมองมีวัตถุประสงค์เพื่อป้องกันการค้นหามุมมองทุกครั้งที่รายการถูกผูกไว้กับตัวยึดไม่ใช่การสร้างครั้งแรก
— stuckj

2
getPosition()เลิกใช้getAdapterPosition()หรือgetLayoutPosition()แทนที่
— K Neeraj Lal

94

จากคำตอบของ Jacob Tabak (+1 สำหรับเขา) ฉันสามารถเพิ่มผู้ฟัง LongClick:

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

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

        void onItemLongClick(View view, int position);
    }

    private OnItemClickListener mListener;

    private GestureDetector mGestureDetector;

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

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

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

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

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

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

        return false;
    }

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

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

จากนั้นคุณสามารถใช้สิ่งนี้:

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

    @Override
    public void onItemLongClick(View view, int position) {
        // ...
    }
}));

1
ใช้เวลาสักครู่ในการปรับตัวเข้ากับแอพของฉันและจัดแนวและจัดรูปแบบโค้ดให้เป็นมาตรฐาน Java / Android แต่ในที่สุดมันก็ใช้งานได้ดี
— milosmns

คุณจะเพิ่มภาพเคลื่อนไหวสำหรับการคลิกที่ยาวนานได้อย่างไร
— Jon

1
@ ผลคลิก Eng.Fouad ไม่ทำงานโดยใช้นี้แม้ว่าถ้าเราฟังคลิกตั้งอยู่ในผลอะแดปเตอร์คลิกทำงานแก้ปัญหาใด ๆ นี้
— ingsaurabh

4
คุณควรจะแทนที่ public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
— Paolo Rotolo

ด้วยเหตุผลบางอย่างมันไม่ส่งคืนมุมมองที่ถูกคลิก ในกรณีของฉันฉันคลิกที่ช่องทำเครื่องหมาย แต่มุมมองที่กำหนดเป็นสิ่งที่แตกต่างกัน วิธีที่ฉันตรวจสอบ:view.getId() == R.id.selection
— dVaffection

63

นี่คือสิ่งที่ได้ผลสำหรับฉัน แนบไปOnClickListener onBindViewฉันไม่รู้จริงๆว่าสิ่งนี้จะส่งผลกระทบต่อประสิทธิภาพหรือไม่ แต่ดูเหมือนว่าจะทำงานได้ดีเมื่อใช้รหัสน้อย

public void onBindViewHolder(ViewHolder holder, final int position) {
    holder.view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "Recycle Click" + position, Toast.LENGTH_SHORT).show();
            }
    });
}

5
ในกรณีของฉัน holder.itemView.setOnClickListener (.. )
— D4rWiNS

18
มันมีชื่อว่า 'itemView' แทนที่จะเป็น 'view' ในกรณีของฉันเพียงแค่พูดสำหรับผู้เริ่มต้นบางคนไม่เข้าใจสิ่งที่พวกเขากำลังคัดลอกและไม่สามารถคิดได้ว่าทำไมไม่ทำงาน
— D4rWiNS

3
มันเป็นตำแหน่งเลย์เอาต์
— Bubunyo Nyavor

1
สำหรับฉันดูเหมือนว่าจะใช้กับรายการที่มองเห็นได้ครั้งสุดท้ายเท่านั้นไม่ใช่รายการที่คลิก
— Nasz Njoka Sr.

2
วิธีนี้ดูเหมือนจะดีที่สุดสำหรับฉัน แต่สิ่งนี้แตกต่างจากคำตอบของ @bolot ในการทำงานที่มีประสิทธิภาพอย่างไร เขาได้ใช้ ViewOnClickListener โดยตรงในคลาส ViewHolder ซึ่งแยกวิธีการ onClick ออกจากกัน ซึ่งจะเป็นทางออกที่ดีที่สุด?
— Edmond Tamas

46

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

ฉันมีประเพณี OnClickListenerอินเทอร์เฟซที่มีในรายการคลิกเหตุการณ์ซึ่งเก็บมุมมองของรายการที่ถูกคลิกและตำแหน่งรายการจากอะแดปเตอร์ ฉันนำเสนออินสแตนซ์ของมันในตัวสร้าง (หรืออาจเป็นกับ setter) และแนบไปที่ฟังดูคลิกฟังคอนเทนเนอร์

ฉันยังมีฟังคลิกอื่น ๆ ในอะแดปเตอร์ (สามารถอยู่ในมุมมองผู้ถือ) ซึ่งจะจัดการคลิกดูปัจจุบันจากภาชนะ

 public class MyRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> {

private ArrayList<String> mData;
private OnItemClickListener mOnItemClickListener;

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

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

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

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

    final MyViewHolder viewHolder = new MyViewHolder(layoutView);

    viewHolder.container.setOnClickListener(new OnClickListener() {

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

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

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

    return viewHolder;
}

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

ในกิจกรรมที่คุณต้องเริ่มต้นอะแดปเตอร์โดยผ่านอินสแตนซ์ของ OnItemClickListener

public class FeedActivity extends ActionBarActivity {

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

    ...

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

    .....

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

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

            ///list item was clicked
        }
    });

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

และ ViewHolder ของฉัน

public class MyViewHolder extends RecyclerView.ViewHolder {

public Button button;
public View container;

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

    container = itemLayoutView;
    button = (Button) itemLayoutView.findViewById(R.id.button);
}}

วิธีนี้ใช้ได้ผลดีสำหรับฉัน - หมายความว่าคุณสามารถจัดการการคลิกในกิจกรรมได้มากกว่าภายในมุมมองกริด
— leafcutter

3
ฉันจะให้เงินคุณได้ที่ไหน 4 ชั่วโมงในการค้นหาจากนั้นฉันอ่านโพสต์ของคุณ ขอบคุณสำหรับเวลาที่คุณโพสต์ข้อความนี้
— Brandon

3
ฟังดูงี่เง่า แต่มีหน่วยความจำหรือประสิทธิภาพเช่นปัญหาหรือไม่ เพราะเรากำลังกำหนดฟังการคลิกทุกครั้งที่มีการดึงมุมมองใช่ไหม
— rgv

1
@Raghav ใช่ทุกครั้งที่มีการดูการผูก listener การคลิกใหม่จะถูกกำหนด แต่นี่เป็นโฟลว์มาตรฐาน แต่ mOnItemClickListener ถูกสร้างเพียงครั้งเดียวสำหรับอแด็ปเตอร์เพียงแค่มุมมองและตำแหน่งของมันจะแตกต่างกันในการคลิกแต่ละรายการ;)
— Sir NIkolay Cesar The First

3
ตัวอย่างที่ดีในการฆ่าประสิทธิภาพแอพและสร้างความจำที่มากเกินไป! ด้วยตัวอย่างนี้คุณเพียงแค่ต้องใช้สโครลเพื่อสร้างวัตถุที่ไร้ประโยชน์หลายร้อยรายการซึ่งในไม่ช้าก็จะไร้ประโยชน์และจะต้องเข้าถึงได้ในรูปแบบ garbige @NoobDogg ถูกต้อง ClickListeners ไม่ได้ถูกสร้างขึ้นที่ onBindView ต้องสร้าง listener การคลิกหนึ่งครั้งใน onCreateView (หรือ constructor holder) และมีอยู่ในขณะที่เราต้องการหน้าจอที่มีอะแดปเตอร์นี้
— Mykola Tychyna

36

นี่คือสิ่งที่ฉันต้องการในกรณีที่มีคนพบว่ามีประโยชน์:

public static class ViewHolder extends RecyclerView.ViewHolder {

    public ViewHolder(View item) {

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

    }
}

ที่มา: http://blog.csdn.net/jwzhangjie/article/details/36868515


ทุกรุ่นที่ฉันลองนี่เป็นรุ่นที่ฉันใช้งานได้ แต่มันก็โอเคที่จะทำอย่างนั้น? หรือมีวิธีที่ดีกว่าเช่นการปฏิบัติที่ดีที่สุด?
— Matthias Loibl

1
เท่าที่ฉันจะบอกได้นี่เป็นวิธีเดียวเท่านั้น ลองดูรายละเอียดเพิ่มเติม! stackoverflow.com/a/24933117/1508887
— Fifer Sheep

ฉันจะเปิดแฟรกเมนต์ใหม่จากวิธี onclick ภายในได้อย่างไร
— แฮ

5
getAdapterPosition () แทนที่ getPosition ()
— Kennedy Nyaga

27

ผมมีทางออกที่ดีสำหรับRecyclerView's onItemClickListenerสำหรับรายการและไอเทมย่อย

ขั้นตอนที่ 1-สร้างอินเทอร์เฟซ

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

ขั้นตอนที่ 2-จากนั้นใช้ในonBindViewHolderวิธีของอะแดปเตอร์ด้วยวิธีต่อไปนี้

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

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

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

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

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

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

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

    }

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

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

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

    }

ขั้นตอนที่ 3ค้นหาและตั้งค่ามุมมองรีไซเคิลในกิจกรรมหรือส่วนที่คุณใช้งานอยู่

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

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

ขั้นตอนที่ 4 -ใช้อินเทอร์เฟซในกิจกรรมหรือส่วนที่คุณใช้ recyclerview

@Override
    public void onRecyclerViewItemClicked(int position, int id)
    {
        if(id==-1){
            Toast.makeText(mActivity, "complete item clicked", Toast.LENGTH_LONG).show();
        }else{
            Toast.makeText(mActivity, "setting button clicked", Toast.LENGTH_LONG).show();
        }
    }

2
นี่เป็นทางออกที่ดีที่สุดเพราะปกติเราต้องการคุณสมบัติมากมายจากกิจกรรม / แฟรกเมนต์ใน onItemClickListener ของเราและไม่มีเหตุผลที่จะเรียกมันโดยตรงจากผู้ชม (ฉันจะต้องสร้างคอนสตรัคเตอร์ที่กำหนดเองสำหรับแต่ละอะแดปเตอร์) โดยวิธีการที่รหัสของคุณเป็น extense เล็กน้อยฉันขอแนะนำให้คุณตัดเป็นส่วนที่สำคัญที่สุด (setOnItemClickListener)
— sagits

นี่เป็นวิธีการง่ายๆที่ดีสำหรับการแยกแยะแถว / ไอเท็มจากรายการย่อย
— Nigel Savage

17

นี่คือสิ่งที่ฉันทำ โซลูชันนี้รองรับทั้ง onClick และ onLongClick ทั้งใน RecyclerView Items และ Views ภายใน RecyclerView Items (มุมมองภายใน)

ฉันติดแท็กมุมมองผู้จัดวางบนมุมมองที่ฉันเลือก:

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

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

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

    return viewHolder;
}

และฉันใช้ holder.getPosition () เพื่อดึงตำแหน่งใน onClick () วิธี (onLongClick คล้าย):

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

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

ตัวแปรที่มี getChildPosition ก็สามารถใช้ได้เช่นกัน โปรดทราบว่าสำหรับมุมมองภายในใช้ onClick ():

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

ในใจของฉันข้อได้เปรียบของการแก้ปัญหานี้คือเมื่อคลิกที่รูปเพียงฟังรูปเท่านั้นที่เรียกว่า onclick () ในขณะที่เมื่อฉันรวมโซลูชันของ Jacob สำหรับมุมมองรายการ RecyclerView และโซลูชันของฉันสำหรับมุมมองภายในมุมมอง RecyclerView Item onclick ( ) เรียกอีกอย่างว่า (เมื่อคลิกที่ภาพ)


11

มีวิธีที่ง่ายกว่ามากในการทำเช่นนี้ เพียงใช้กับการคลิกในonBindViewHolderมุมมองราก

พิจารณาว่านี่เป็นมุมมองของคุณสำหรับอะแดปเตอร์

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

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

จากนั้นทำตามในอะแดปเตอร์ของคุณ

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

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

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

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

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

    protected LinearLayout linearlayout = null
    protected TextView textview = null;

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

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

9

คุณสามารถผ่านไปclickListenerAdapter

ในActivity:

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

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

จากนั้นส่งไปที่Adapter:

MainAdapter mainAdapter = new MainAdapter(this, mItemClick);

ในAdapter's onCreateViewHolder:

 @Override
public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
    View itemView = activity.getLayoutInflater().inflate(R.layout.main_adapter_item, viewGroup, false);
    ViewHolder holder = new ViewHolder(itemView);
    itemView.setOnClickListener(mItemClick);
    return holder;
}

คุณจะส่งผ่านholderค่าผ่านความตั้งใจได้อย่างไร
— RoCk RoCk

8

ฉันได้พัฒนาไลบรารี่แบบเบาสำหรับ 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
            }
        });

สามารถยืนยันได้ห้องสมุดนี้ยอดเยี่ยมมาก! ใช้งานง่ายดีมาก!
— peterkodermac

7

คุณสามารถใช้ OnClickListener กับคลาส ViewHolder ของคุณ

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

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

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

และ onBindViewHolder ตั้งค่ารายการมุมมองของคุณ

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

7

วิธีง่ายเกินไปและมีประสิทธิภาพ

แทนที่จะใช้อินเทอร์เฟซView.OnClickListenerภายในตัวยึดมุมมองหรือการสร้างและอินเทอร์เฟซและการใช้อินเทอร์เฟซในกิจกรรมของคุณ - ฉันใช้รหัสนี้เพื่อง่าย ๆ ใน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();
        }
    }

3
นี่เป็นวิธีปฏิบัติที่ไม่ดีทั่วไปเพราะดูง่ายเกินไป คุณกำลังสร้างฟังภายในใหม่ทุกครั้งที่มีการผูกวัตถุ (และแต่ละรายการใน recycler สามารถผูกหลายครั้ง) ซึ่งไม่ดีสำหรับ a) ประสิทธิภาพ b) การรวบรวมขยะ แต่คุณควรสร้างผู้ฟังหนึ่งคนที่ใดที่หนึ่ง (ใน viewholder, ในอะแด็ปเตอร์, ในแฟรกเมนต์หรือกิจกรรม) และเพิ่มไปยังไอเท็มในตัวสร้างวิวเวอร์ใน onCreateViewHolder นี่คือความซับซ้อนที่เพิ่มขึ้นของการคิดว่ารายการใดเป็น clicker แต่สามารถแก้ไขได้อย่างง่ายดายผ่านแท็กหรือเพิ่มข้อมูลเพิ่มเติมให้กับผู้ถือ
— GuillermoMP

6

คำตอบที่โพสต์ทั้งหมดเป็นวิธีแก้ปัญหาที่ยอดเยี่ยมอย่างไรก็ตามหากคุณไม่ต้องการจัดการกับรายละเอียดการติดตั้งที่มากเกินไปและเพียงต้องการให้มันทำงานคล้ายกับที่ ListView ทำฉันจะแนะนำให้ใช้ TwoWay-View ดังที่เห็นที่นี่:

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

โปรดทราบว่าการใช้งานนี้ยังสนับสนุนการกดแบบยาวในรายการรวมถึงการสนับสนุนสำหรับสถานะแบบกด (ซึ่งเป็นสิ่งสำคัญที่โซลูชันอื่น ๆ สำหรับคำถามนี้ขาด)

หากคุณไม่ต้องการใช้ทั้งไลบรารีลองดูที่คลาสClickItemTouchListenerซึ่งสามารถใช้เป็นแบบสแตนด์อโลนได้หากจำเป็น ปัญหาเดียวที่ฉันพบในขณะนี้คือด้วยการกดแบบยาว + การเลื่อนดูเหมือนว่าจะมีพฤติกรรมที่ไม่ถูกต้อง


6

ถ้าคุณต้องการที่จะจับเหตุการณ์การคลิกในแต่ละรายการจากนั้นนำไปใช้OnClickListenerในViewHolderชั้นเรียนแล้วตั้งค่าฟังคลิกในมุมมองของแต่ละบุคคลหรือทั้งหมดitemViewการเรียนและการตั้งค่าแล้วคลิกฟังในมุมมองของแต่ละบุคคลหรือทั้งหมด

ตัวอย่างต่อไปนี้แสดงให้เห็นเหมือนกัน

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

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

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

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

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

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

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

    }
} 

5

สำหรับฉันนี่เป็นวิธีที่ดีที่สุด:

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

3
getChildPosition () ถูกตัดหัว
— Nasz Njoka Sr.

5

RecyclerViewไม่ได้OnClickListenerและจะต้องใช้มันเอง

ผมชอบที่จะเพิ่มOnItemClickListenerอินเตอร์เฟซในAdapterที่มีวิธีการเรียกเมื่อคุณคลิกที่มุมมองรายการจากonClick ViewHolderดังนั้นความรับผิดชอบในการจัดการการคลิกที่รายการนั้นอยู่นอกViewHolderและAdapterและกิจกรรมหรือส่วนที่จะตัดสินใจว่าจะทำอย่างไร

เพิ่มส่วนต่อประสานกับผู้ฟังและวัตถุผู้ฟัง

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

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

  ...
}

เราจับภาพการคลิกของมุมมองรูทของรายการและเมื่อการเรียกกลับถูกเรียกใช้onClickฟังอะแดปเตอร์

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

  ...

  private static OnItemClickListener onItemClickListener;

  ...

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

  ...

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

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

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

เนื่องจากกิจกรรมหรือส่วนย่อยส่วนในกรณีของเราเรากำหนดผู้ฟังให้กับอะแดปเตอร์และการเรียกกลับ onClick เราจะได้รับรายการที่เลือกตามตำแหน่งและเปิดกิจกรรมรายละเอียดของรายการ

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

5

แต่น่าเสียดายที่RecyclerViewจะหายไปคู่ของคุณสมบัติที่ListViewมีในตัว ตัวอย่างเช่นความสามารถในการเพิ่มOnItemClickListenerทริกเกอร์ที่เมื่อมีการคลิกรายการ RecyclerViewช่วยให้คุณสามารถตั้งค่าOnClickListenerในอะแดปเตอร์ของคุณ แต่ผ่านการฟังการคลิกที่จากรหัสโทรของคุณไปยังอะแดปเตอร์และไปที่ViewHolderมีความซับซ้อนสำหรับการจับคลิกรายการที่เรียบง่าย

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

    @Override
    public void onChildViewDetachedFromWindow(View view) {

    }
};

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

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

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

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

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

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

public interface OnItemClickListener {

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

public interface OnItemLongClickListener {

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

คุณต้องกำหนดR.id.item_click_supportโดยใช้ ids.xml:

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

ขณะนี้ผู้ฟังการคลิกรหัสที่เป็นผลลัพธ์มีลักษณะดังนี้:

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

สำหรับคำอธิบายโดยย่อเกี่ยวกับการคลิกที่ recyclerview โปรดดูที่littlerobots_blog


5

คุณสามารถกำหนดsetOnClickListenerในคลาส ViewHolder ของคุณได้อย่างง่ายดายดังนี้:

public class ViewHolder extends RecyclerView.ViewHolder {
    TextView product_name;

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

5

นี่คือสิ่งที่ฉันทำอ่านเพิ่มเติมและดาวน์โหลดส่วนสำคัญที่นี่

เพิ่มเหมือนกันที่นี่

CustomItemClickListener.java

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

ItemsListAdapter.java

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

Context mContext;
CustomItemClickListener listener;

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

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


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

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

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

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

4

จากคำตอบส่วนใหญ่ข้างต้นดูเหมือนว่าพวกเขากำลังตั้งค่าตัวเลือกผู้ประกาศในรายการแต่ละรายการ อย่างไรก็ตามการแก้ปัญหาที่ฉันกำลังจะนำเสนอนั้นง่ายมาก แต่ก็ไม่ง่ายนักสำหรับหลาย ๆ คน หลายคนลืมว่าส่วนประกอบอื่น ๆ มักจะอยู่ในองค์ประกอบหลักที่ใช้ในการแสดงรายการในมุมมองรายการหรือรีไซเคิล วิธีการแก้ปัญหานี้เป็นเพียงเกี่ยวกับการตั้งค่าฟังเดียวคลิกเพื่อดูผู้ปกครองนี้และเปิดเล่น การแก้ปัญหายังรวมถึงวิธีการส่งผ่านตำแหน่งของรายการที่ถูกคลิกจากรายการหรือมุมมองรีไซเคิล ที่นี่รูทวิวหลักของเราคือ CardView จากห้องสมุดสนับสนุน android นี่คือตัวอย่างรหัส

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

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

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

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

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

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

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

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

            }
        });

    }
}

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

}


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

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

    }
}
}

4

การใช้ Kotlin ใน คำตอบของ nhaarman :

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

            }

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

            }
}){})

RecyclerItemClickListener.java:

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


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

    private var mGestureDetector: GestureDetector

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

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

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

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

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

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

    override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
}

3
public class MyViewHolder extends RecyclerView.ViewHolder {
        public TextView title, year, genre;

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

3

นี่คือรหัสที่สมบูรณ์สำหรับอะแดปเตอร์ที่กำหนดเองของฉันรหัสนี้จะขยายแถวด้วยรายการที่กำหนดไว้ในไฟล์ xml ชื่อ "list_item" มันจะทำการคลิกเหตุการณ์ในแถวรายการทั้งหมดที่มีตำแหน่งตามลำดับ

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

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

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

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

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

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

    }

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

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

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

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

2

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

เป้าหมายของเรา:

  1. ผู้ดูควรรู้อะไรเกี่ยวกับคลาสที่ตอบสนองต่อเหตุการณ์ยกเว้นว่าจะใช้อินเทอร์เฟซที่แน่นอน
  2. ตัวจัดการการคลิกควรรับตำแหน่งใน RecyclerView ของมุมมองที่คลิก
  3. เราควรจะสามารถแยกแยะได้ว่ามุมมองที่ถูกคลิกในช่องใส่มุมมอง
  4. รักษาคัปปลิ้งหลวมระหว่างส่วนประกอบทั้งหมดและไม่ทำให้เกิดรอบการเก็บรักษาใด ๆ

ขั้นตอน:

  1. สร้างอินเทอร์เฟซเพื่อจัดการการตอบสนองการคลิก

  2. ใช้อินเทอร์เฟซนี้ในกิจกรรมที่จะจัดการการคลิก

  3. เพิ่มตัวแปรสมาชิกใน RecyclerView Adaptor เพื่อเก็บ Weak Reference และ Constructor ที่ตั้งค่าไว้

  4. ทำเช่นเดียวกันใน RecyclerView ViewHolder และเพิ่มตัวแปรสมาชิกเพื่อติดตามตำแหน่ง

  5. ตั้งค่าให้ผู้ฟังคลิกของคุณในมุมมองใด ๆ ที่คุณต้องการใน ViewHolder จากนั้นโทรกลับไปที่ผู้ตอบคำถามเพื่อจัดการกับพวกเขา

  6. เปลี่ยนเมธอด onBindViewHolder ของคุณเพื่อตั้งค่าตำแหน่งเมื่อเชื่อมโยง

  7. ส่งผู้ตอบกลับไปที่ ViewHolder

  8. ในการตอบกลับตอนนี้คุณสามารถใช้ getId () บนมุมมองเพื่อกำหนดว่ามุมมองใดถูกคลิก

และนี่คือส่วนสำคัญเพื่อให้คุณเห็นว่าทุกอย่างลงตัวเข้าด้วยกันได้อย่างไร: RecyclerViewView handling handling


2

ฉันรู้ว่ามีคำตอบมากมาย แต่ฉันคิดว่าฉันอาจให้การใช้งานของฉันเช่นกัน (รายละเอียดทั้งหมดสามารถพบได้ในคำถามอื่นที่ฉันตอบ )

ดังนั้นเพื่อเพิ่มฟังคลิกภายในของคุณระดับความต้องการที่จะดำเนินการViewHolder View.OnClickListenerนี้เป็นเพราะคุณจะตั้งค่าOnClickListenerให้กับitemViewพารามิเตอร์ของViewHolderคอนสตรัค 's ให้ฉันแสดงสิ่งที่ฉันหมายถึง:

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

    TextView text1, text2;

    ExampleClickViewHolder(View itemView) {
        super(itemView);

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

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

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

สิ่งอื่น ๆ ที่คุณต้องเพิ่มเท่านั้นคือส่วนต่อประสานที่กำหนดเองสำหรับคุณ Adapterและตัวตั้งค่า:

private OnEntryClickListener mOnEntryClickListener;

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

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

ดังนั้นการสนับสนุนคลิกใหม่ของคุณ Adapterเสร็จสมบูรณ์

ตอนนี้มาใช้มันกันเถอะ ...

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

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

นอกจากนี้คุณยังสามารถดูชุดตัวอย่างที่ฉันทำกับ Gist นี้ใน GitHub:

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


คุณควรใช้ getAdapterPosition () แทน getLayoutPosition ()
— BladeCoder

2

นี่คือสิ่งที่ฉันทำเพื่อนำมาใช้ใหม่ OnClickListener

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

ใน ViewHoder ใช้พาเรนต์ของการเลย์เอาต์รายการ

  public class MyviewHolder extends RecyclerView.ViewHolder {

       LinearLayout linearLayout_item;

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

ในแท็กชุด onBindViewHolder เป็นตำแหน่ง

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

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

และใน Onclick

 @Override
public void onClick(View v) {

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

            // do some thing with position 

            break;
    }
}

2

สำหรับฉันวิธีที่สะอาดในการทำเช่นนี้คือ

ตัวสร้างอะแดปเตอร์

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

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

         }

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

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

อินเทอร์เฟซที่เชื่อมโยง

private interface EnvironmentTypeRecyclerViewAdapterListener
{
    void onListItemSelected(Environment environment);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.