왜 RecyclerView에 onItemClickListener ()가 없습니까?


965

나는 탐험 RecyclerView하고 있었고 그것이 RecyclerView없는 것을보고 놀랐습니다 onItemClickListener().

두 가지 질문이 있습니다.

주요 질문

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 (this)를 추가해야합니다. ViewHolder 생성자에서.
whitneyland

3
좋은 질문을했습니다 ... 많은 개발자들이 RecyclerView와 ListView에 대해 같은 의심을 가지고 있습니다.
venkat

17
질문 : RecyclerView에 OnItemClickListner ()가없는 이유는 무엇입니까? 2를 제외한 아래의 모든 답변 : RecyclerView에 onclick을 추가하는 방법
Manohar Reddy

2
누군가가 실제로 답변을하기 위해 시간을 내기를 바랍니다.QUESTION
Ojonugwa Jude Ochalifu

1
성능 및 가비지 메모리 문제로 인해 제거했다고 생각합니다. 그러나 받아 들인 대답을 살펴보십시오 .... 같은 문제가 발생합니다. 나는 당신이 그것을 받아 들여 실수를했다고 생각하고 다른 ppl은 당신 때문에 실수를합니다 :).
Alex

답변:


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한 단계 더 걸립니다과 행 / 열의 개념이없는, 오히려 아이들의 임의의 배치 양, 그들은 그들의 각 하나에 온 클릭을 위임 한 또는 프로그래머 구현에.

1 : 1 교체가 아니라 복잡한 사용 사례를위한보다 유연한 구성 요소 Recyclerview로 생각하십시오 ListView. 그리고 당신이 말한 것처럼 귀하의 솔루션은 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()은 더 이상 사용되지 않습니다. "이 방법은 어댑터 업데이트의 비동기 처리로 인해 그 의미가 모호하기 때문에 더 이상 사용되지 않습니다. 사용 사례에 따라 {@link #getLayoutPosition ()} 또는 * {@link #getAdapterPosition ()}을 사용하십시오. "
upenpat

8
몇 가지 옵션이 있습니다. 뷰 홀더 내부의 int 필드에 위치를 넣고 바인딩하는 동안 업데이트 한 다음 클릭시 반환하십시오.
MLProgrammer-CiM

8
@ MLProgrammer-CiM "여러 가지 옵션이 있습니다. 뷰 홀더 내부의 int 필드에 위치를 지정하고 바인딩하는 동안 위치를 업데이트 한 다음 클릭시 반환하는 것이 하나입니다." ViewHolder에는이 값이 이미 설정되어 있습니다. 전화하십시오viewHolder.getPosition();
Chad Bingham

104

RecyclerView에없는 이유 onItemClickListener

RecyclerView이전의 대조적으로, 도구 상자입니다 ListView그것은 기능과 유연성 덜 빌드를 가지고있다. 이 onItemClickListener있는 ListView에서 제거되는 유일한 기능이 아닙니다. 그러나 원하는대로 확장 할 수있는 청취자와 방법이 많이 있습니다. 오른손에 훨씬 강력합니다.).

제 생각에는 가장 복잡한 기능 RecyclerView빠른 스크롤 입니다. 다른 기능의 대부분은 쉽게 다시 구현할 수 있습니다.

다른 멋진 기능을 RecyclerView추가 하려면 다른 질문에 대한 답변을 읽으십시오 .

메모리 효율적-onItemClickListener를위한 드롭 인 솔루션

이 솔루션이되었습니다 제안 에 의해 우고 프랜트 , 안드로이드 GDE, 직후에 RecyclerView발표되었다. 그는 코드를 작성하여 사용하기 위해 무면허 클래스를 만들었습니다.

RecyclerView을 사용하여 도입 된 다목적 성을 보여줍니다 RecyclerView.OnChildAttachStateChangeListener.

2019 편집 : Hugo Visser의 kotlin 버전, Java one, 아래 유지

코 틀린 / 자바

파일을 작성 values/ids.xml하고 여기에 넣으십시오.

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

그런 다음 아래 코드를 소스에 추가하십시오.

코 틀린

용법:

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

(또한 긴 항목 클릭을 지원하며 추가 한 다른 기능에 대해서는 아래를 참조하십시오).

구현 (Hugo Visser Java 코드에 대한 나의 적응) :

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 파일도 추가해야합니다)

코 틀린 버전의 보너스 기능

때로는 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스크롤 하는 동안 계속 파괴하고 작성하기 때문에 다른 솔루션보다 더 효율적 입니다.

더 필요한 경우 홀더 자체를 돌려 주도록 코드를 조정할 수도 있습니다.

최종 비고

제안 된 다른 답변과 같이 목록의 각보기에서 클릭 리스너를 설정하여 어댑터에서 처리하는 것이 좋습니다.

가장 효율적인 방법은 아니지만 (보기를 재사용 할 때마다 새 리스너를 작성) 작동하지만 대부분의 경우 문제가되지 않습니다.

또한 문제의 분리에 약간의 영향을 미쳐 실제로 클릭 이벤트를 위임하는 것은 어댑터의 작업이 아닙니다.


생성자에 addOnChildAttachStateChangeListener가 있고 절대 제거하지 않습니까?
사바

@Saba 당신은 생성자를 직접 사용하지 않고 정적 메소드 addTo()와를 통해 사용해야합니다 removeFrom(). 인스턴스는 recyclerview 태그와 연관되어 있으며 태그와 함께 또는 수동으로 제거 될 때 종료됩니다.
다니엘 세가 토

클릭 코드 리스너를 설정하기 만하면됩니다 onCreateViewHolder.
EpicPandaForce

귀하의 주장은 흐름에 달려 있습니다. 코드의 양이 아니라 효율성과 책임 원칙에 관한 것이며 코드의 양은 특히 코드가 재사용 가능하고 효율적일 때 좋은 / 나쁜 해결책을 잘 나타내지 않습니다. 라이브러리 포함으로 간주 할 수있는 프로젝트에 해당 코드를 입력하면에 대한 1 줄 RecyclerView입니다.
다니엘 세가 토

@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); 이제는 recyclerView를 사용하지 않습니다. indexOfChild (v);
Qadir Hussain

4
스크롤 할 때 문제가 없습니까? 내 테스트에서 itemPosition은 뷰 재활용에 의존하는 것처럼 보이므로 어댑터의 전체 목록과 비교할 때 잘못되었습니다.
Simon

16
recyclerViewMyOnClickListener에 들어가는 방법 ?
guo

3
다음을 사용하는 대신 : int itemPosition = recyclerView.indexOfChild (v); 다음을 사용해야합니다. RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder (v); int itemPosition = holder.getAdapterPosition ();
Gordon Freeman

35

Android Recyclerview with 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

트윗 담아 가기 사용 후 포커스 변경의 충돌을 피하는 가장 좋은 방법이라고 생각합니다SwipeRefreshLayout
NickUnuchek

이것은 완전히 불필요합니다. 터치를 가로채는 대신 View.OnClickListener를 사용할 수 있습니다.
EpicPandaForce

23

@marmor 덕분에 답변을 업데이트했습니다.

ViewHolder 클래스 생성자 에서 onClick ()을 처리하고 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재설정되므로 단일 항목 을 작성해도 도움이되지 않습니다 . @ MLProgrammer-CiM 솔루션을 참조하십시오. OnClickListeneronBindViewHolder()
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

첫 번째 :이 공용 인터페이스 OnCardClickListner와 같이 OnCardClickListner 인터페이스에 OnProductClicked라는 메소드를 추가해야합니다. {void OnCardClicked (View view, int position); 무효 OnProductClicked (보기, int 위치); } 둘째 : 다음과 같이 제품 아이콘에 클릭 리스너를 구현하십시오. holder.yourProductIcon.setOnClickListener (new View.OnClickListener () {@ public void onClick (View v) 재정의 {onCardClickListner.OnProductClicked (v, position);}});
waqas ali

OnCardClicked를 재정의 할 수 없습니다. 사람들은이 답변을 어떻게지지합니까?
The_Martian

19

> RecyclerView는 Listview와 어떻게 다릅니 까?

한 가지 차이점이 있다는 것입니다 LayoutManager당신이 관리 할 수있는 RecyclerView와 클래스 RecyclerView같은 -가

가로 또는 세로 스크롤LinearLayoutManager

에 의해 GridLayout GridLayoutManager

스 태거 드 그리드 StaggeredGridLayoutManager

RecyclerView의 가로 스크롤과 유사합니다.

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

15

후속 MLProgrammer-CIM의 우수한 RxJava 솔루션

클릭 수 소비 / 관찰

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()제거되었다. 그냥 돌아 PublishSubject이다 Observable.


조금만 설명해 주시면 두 번째 줄에서 mClickConsumer를 어디서 구할 수 있습니까? rxAdapter.getPositionClicks (). subscribe (mClickConsumer);
bluetoothfx

14

예를 들어 보자 ...

  • onClick () 처리
  • 커서-RecyclerView
  • 홀더 유형

    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

나는이 방법을 매우 간단하게 수행했다.

그냥 추가 한 라인을 위한 클릭 수 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는 onItemClickListenerRecyclerView가 재활용 (놀람!)하기 때문에 책임을지지 않으므로 수신 된 클릭 이벤트를 처리하기 위해 재활용되는 뷰의 책임입니다.

실제로 여러 위치에서 클릭 할 수있는 항목이있는 경우 사용하기가 훨씬 쉽습니다.


어쨌든 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
        }
    }
}

코 틀린의 동일한 코드 :

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.) RxJava에서 PublishSubject / PublishRelay가 필요하지 않습니다.

클릭 리스너를 사용하십시오.


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 ()을 추가하려면 다음과 같이 자신의 RecyclerView.Adapter의 onCreateViewHolder ()에서 쉽게 수행 할 수 있습니다.

        @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를 임시로 저장하십시오 (이것은 예제를 작성하는 것이 좋습니다).

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

어댑터로 돌아가서 ViewHolder가 바인드 될 때 현재 POJO를 설정하십시오 (또는 현재보기에없는 경우 널로 설정).

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

인터페이스를 Object 메소드처럼 구현하려고합니다. 작동하지 않습니다
Akshay

업데이트 : 당신이 필요로하는 것mMyAdapter.setOnItemClickListener(MyAdapter.OnItemClickListener() {});
Akshay

@ Akshay 죄송하지만 코드가 정확하다고 생각합니다. 해봤 어? 안드로이드의 모든 리스너는 동일한 원칙을 따르고 'new'로 인터페이스를 인스턴스화해야합니다 (예 : 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에 대한 일부 블로그를 읽고 일부 어댑터 라이브러리를 연구하십시오. FlexibleAdapter, FastAdapter 등과 같은 Github에는 이미 많은 것이 있습니다.
Davideas

1
답변은 상대적으로 인기가 높은 답변이 많고 페이지 하단에 비교적 새롭기 때문에 여전히 0 표를 얻습니다. 그건 그렇고, 새 코드에서는을 사용해야합니다 getAdapterPosition().
Davideas

두 메소드의 javaDoc을 읽으면됩니다.
Davideas

3

적절한 방법으로 모든 것을 구현 한 것을 확인하십시오.

RecyclerViewHolder 클래스

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(). notify () 메소드 후에 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

뷰 홀더 내부에서 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();
        }
    }

2
그리고 각 onBind () 메소드 호출에서 새로운 OnItemClickListener 객체를 생성하는 것이 좋은 접근 방법이라고 생각하십니까?
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 ()가 없는가?"입니다. NOT "RecyclerView에서 onItemClickListener ()를 구현하는 방법?" .
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

안드로이드 리사이클 러보기 항목 클릭 이벤트를 처리하는 라이브러리를 작성했습니다. 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;
        }
    });

RecyclerView.ViewHolder와 같은 BaseViewHolder
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;
    }
}

tags.xml 파일에 다음과 같이 정의 된 TAG_POSITION

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