RecyclerViewにonItemClickListener()がないのはなぜですか?


965

私は探検していてRecyclerView、それRecyclerViewがないのを見て驚いたonItemClickListener()

2つの質問があります。

主な質問

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コンストラクタで。
ホイットニーランド2015年

3
あなたはいい質問をしました...多くの開発者はRecyclerViewとListViewについて同じ疑問を持っています。
venkat

17
質問: RecyclerViewにOnItemClickListner()がないのはなぜですか?2を除くすべての回答: RecyclerViewのonclickを追加する方法
Manohar Reddy

2
誰かが実際に答えるために時間を割いてほしいと思いますQUESTION
Ojonugwa Jude Ochalifu '

1
パフォーマンスとガベージメモリの問題のため、削除されたと思います。しかし、受け入れられた答えを見てください...同じ問題が発生します。私はあなたがそれを受け入れることで間違いを犯したと思います。
アレックス

回答:


1207

tl; dr 2016 RxJavaとPublishSubjectを使用して、クリックのObservableを公開します。

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

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

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

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

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

元の投稿:

の導入以来ListViewonItemClickListener問題がありました。内部要素のいずれかのクリックリスナーがあると、コールバックはトリガーされませんが、通知されていないか、ドキュメント化されていなかったため(そうした場合でも)、多くの混乱とSOの質問がありました。

それRecyclerViewがさらに一歩進んで行/列の概念がなく、任意にレイアウトされた量の子があることを考えると、onClickをそれぞれの子またはプログラマーの実装に委任しました。

考えRecyclerviewないとしてListView1:1の交換ではなく、複雑なユースケースのためのより柔軟な構成要素として。そしてあなたが言うように、あなたの解決策はグーグルがあなたに期待したものです。今、あなたは両方のための正しいパターンである、コンストラクタに渡されたインタフェースへのonClick委任することができ、アダプタ持ちListViewとをRecyclerview

public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {

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

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

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

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

}

そしてあなたのアダプターで

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それに応じて適用する汎用ビューホルダーを作成することもできます。または、1つ上のレベルをオーケストレーターに委任して、複数のフラグメント/アクティビティが同じリストに異なるクリック動作を持つようにします。繰り返しになりますが、すべての柔軟性はあなたの側にあります。

これは本当に必要なコンポーネントであり、これListViewまでの内部実装と改善点にかなり近いものです。グーグルがついに認めたのは良いことだ。


78
RecyclerView.ViewHolderにはgetPosition()メソッドがあります。このコードにいくつかの調整を加えると、位置をリスナーに渡すことができます。
se_bastiaan 2014年

13
onBindViewHolder(holder, position)は、情報が入力されることになっているを完全に見逃しました。
MLProgrammer-CiM 2014年

26
@se_bastiaan getPosition()は非推奨です。「このメソッドは、アダプターの更新の非同期*処理のために意味が曖昧であるため、非推奨です。使用状況に応じて、{@ link #getLayoutPosition()}または* {@link #getAdapterPosition()}を使用してください。 」
upenpat 2015年

8
いくつかのオプションがあります。ビューホルダー内のintフィールドに位置を設定し、バインド中に更新してから、クリックするとそれを返します。
MLProgrammer-CiM 2015年

8
@ MLProgrammer-CiM 「いくつかのオプションがあります。ビューホルダー内のintフィールドに位置を設定し、バインド中に更新してから、クリック時にそれを返します。」 ViewHolderにはすでにこの値があり、すでに設定されています。電話するだけviewHolder.getPosition();
チャドビンガム2015

104

RecyclerViewにない理由 onItemClickListener

これRecyclerViewはツールボックスです。以前ListViewとは異なり、組み込み機能が少なく、柔軟性が高くなっています。onItemClickListenerリストビューから削除されている唯一の機能ではありません。しかし、それはあなたの好みにそれを拡張する多くのリスナーとメソッドを持っています、それは右手ではるかに強力です;)。

私の意見でRecyclerViewは、で削除された最も複雑な機能はFast Scrollです。他のほとんどの機能は簡単に再実装できます。

RecyclerView追加された他のクールな機能を知りたい場合は、別の質問に対するこの回答を読んでください。

メモリ効率-onItemClickListenerのドロップインソリューション

このソリューションは、Android GDEであるHugo Visserによってリリースされた直後に提案されました。彼はライセンスなしのクラスを用意して、コードをドロップして使用できるようにしました。RecyclerView

RecyclerViewを使用して導入された汎用性の一部を紹介しますRecyclerView.OnChildAttachStateChangeListener

Edit 2019:私によるkotlinバージョン、Hugo VisserのJava One、以下に保管

コトリン/ Java

ファイル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ファイルを追加する必要があります)

Kotlinバージョンのボーナス機能

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タグに関連付けられており、それとともに、または手動で削除されたときに終了します。
Daniele Segato

必要なのは、クリックリスナーを設定するだけのコードなので、onCreateViewHolderそれだけです。
EpicPandaForce

あなたの議論は流れました、それはコードの量ではなく効率と責任の原則についてであり、コードの量は特にそのコードが再利用可能で効率的である場合、良い/悪い解決策の大きな指標ではありません。そのコードをプロジェクト(ライブラリのインクルージョンと見なすことができます)に配置したら、必要なのはの1行だけですRecyclerView
Daniele Segato

@DanieleSegatoありがとうございます!
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);
カディールフセイン2015年

4
スクロールするときに問題はありませんか?私のテストでは、itemPositionはビューのリサイクルに依存しているようです。そのため、アダプターの完全なリストと比較すると、問題が発生します。
Simon、

16
recyclerViewMyOnClickListener を取得する方法?
guo

3
使用する代わりに:int itemPosition = recyclerView.indexOfChild(v); 使用する必要があります:RecyclerView.ViewHolderholder = recyclerView.getChildViewHolder(v); int itemPosition = holder.getAdapterPosition();
ゴードンフリーマン

35

Android Recyclerviewを使用するとonItemClickListener、これを試すことがListViewできないのはなぜかというだけです。

出典:リンク

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {

private OnItemClickListener mListener;
public interface OnItemClickListener {
    public void onItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }
    });
}
@Override
public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
    View childView = view.findChildViewUnder(e.getX(), e.getY());
    if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
        mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
    }
    return false;
}

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

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

  }
}

これをRecyclerViewに設定します。

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

7
正直言ってエレガントではありません。
vishal dharankar

@vishaldharankarどうして?使用後のフォーカスの変更の競合を回避する最良の方法だと思いますSwipeRefreshLayout
NickUnuchek

これは完全に不要です。タッチをインターセプトする代わりに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
これは、作成したオブジェクトのガベージコレクトトンスクロールしたときに、あなたの代わりに1 OnClickListenerを作成する必要がありますし、それを再使用します
marmor

2
またonBindViewHolder()、スクロール時に同じビューに対して何度も呼び出されます。シングルOnClickListenerが作成されても、呼び出されるOnClickListenerたびにリセットされるため、役に立ちませんonBindViewHolder()。代わりに@ MLProgrammer-CiMソリューションを参照してください。
vovahost

@ MLProgrammer-CiMソリューションを改善することもMyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() ....できます。この行のすべてのビューにリスナーオブジェクトを作成する代わりに、すべてのビューに単一のリスナーを作成できます。
vovahost

21

みんなはあなたの主な活動でこのコードを使用します。非常に効率的な方法

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

これがあなたのアダプタクラスです。

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


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

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

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

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

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


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

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

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

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

この後、アクティビティでこのオーバーライドメソッドを取得します。

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

5
ユーザーが上下にスクロールすると、OnClickListenerは作成され、何度も繰り返し使用されますか?それは効率的ですか?
Vinh.TV 2016年

カードの更新された位置を取得するために、このマイナーなことが妥協される可能性があります。
waqas ali

こんにちは、その素敵な友達、私は最初にカテゴリと製品の要件アクティビティを持っています、ユーザーがカテゴリアイコンを選択した場合、ダイアログボックスにカテゴリを表示する必要があります。解決方法
Harsha 2016

1つ目:このパブリックインターフェイスOnCardClickListnerのようなインターフェイスOnCardClickListnerにOnProductClickedという名前のメソッドを追加する必要がありますOnCardClickListner {void OnCardClicked(View view、int position); void OnProductClicked(ビューを表示、int位置); 2番目:次のように、製品アイコンにクリックリスナーを実装します。holder.yourProductIcon.setOnClickListener(new View.OnClickListener(){@Override public void onClick(View v){onCardClickListner.OnProductClicked(v、position);}});
waqas ali 2016

OnCardClickedを上書きできません。人々はどのようにこの答えに賛成していますか?
The_Martian 2016

19

> RecyclerViewとListviewの違いは何ですか?

一つの違いがあるということであるLayoutManagerあなたが管理することが可能なRecyclerViewを持つクラスRecyclerViewlike-が

による水平または垂直スクロールLinearLayoutManager

グリッドレイアウト 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


2行目のmClickConsumerはどこにありますか、少し説明してください。rxAdapter.getPositionClicks()。subscribe(mClickConsumer);
bluetoothfx 2018

14

すべてをまとめる方法の例...

  • onClick()の処理
  • カーソル-RecyclerView
  • ViewHolderタイプ

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

11

私がMLProgrammer-CiMの 回答を理解している限り、これを行うことが単に可能です:

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

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


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

9

@ MLProgrammer-CiMの回答を読んだ後、これが私のコードです:

class NormalViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{

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

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

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

「ポジションなし」でgetAdapterPosition戻る可能性があることに注意してください-1
EpicPandaForce

9

私はこのようにして、非常に簡単です:

ただ、追加1つのラインのためにクリックさRecyclerView位置

int position = getLayoutPosition()

ViewHolderクラスの完全なコード:

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

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

これがお役に立てば幸いです。


getAdapterPosition代わりに使用する必要がありますgetLayoutPosition。に対する警戒-1
EpicPandaForce

7

このメソッドを使用して、RecyclerViewからインテントを開始します。

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

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

それは良い方法ではありません。メソッドのonBindViewHolder(...)後で呼び出されないためですnotify()。そのため、状況によってはクリック位置が間違っている可能性があります。
Alex Kisel 2017

5

RecyclerViewはビューのリサイクルをonItemClickListener担当しているため(サプライズ!)、RecyclerViewには理由がありません。したがって、受け取ったクリックイベントを処理するのは、リサイクルされたビューの責任です。

これにより、特に複数の場所でクリックできるアイテムがある場合に、より使いやすくなります。


とにかく、RecyclerViewアイテムのクリックの検出は非常に簡単です。インターフェースを定義するだけです(Kotlinを使用していない場合は、ラムダを渡すだけです)。

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

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

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

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

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

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

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

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

Kotlinの同じコード:

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

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

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

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

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

してはいけないこと実行する必要があります。

1.)タッチイベントを手動でインターセプトする必要はありません

2.)子のアタッチ状態変更リスナーをいじる必要はありません

3.)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を設定します(現在のビューにバインドされていない場合はnullに設定します)。

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

これで、フラグメント/アクティビティから次のように使用できます。

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

オブジェクトメソッドであるかのようにインターフェイスを実装しようとしている。これは機能しません
Akshay

更新:必要なものmMyAdapter.setOnItemClickListener(MyAdapter.OnItemClickListener() {});
Akshay

@Akshay申し訳ありませんが、私のコードは正しいと思います。やってみましたか?Androidのすべてのリスナーは同じ原則に従い、インターフェイスを「新しい」でインスタンス化する必要があります(例:stackoverflow.com/questions/4709870/…
Simon

リスナーは静的であってはなりません。
EpicPandaForce

4

はい、できます

public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {

    //inflate the view 

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

    ViewHolder holder = new ViewHolder(view);

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

return holder;

3

ここでは、複数のonclickを処理できます。以下のコードを参照してください。非常に効率的です。

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

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

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

    public static class FeedHolder extends RecyclerView.ViewHolder implements OnClickListener {

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


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

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

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

        }


        @Override
        public void onClick(View v) {

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

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

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

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

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

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

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

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

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

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

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

        return feedHolder;
    }

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

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


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

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


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


}

彼は意味しましたitemView
Davideas

3

コメントを変更しました...

public class MyViewHolder extends RecyclerView.ViewHolder {

        private Context mContext;

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

            mContext = itemView.getContext();

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

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

                }
            });
        }

1
これは提案ですが、多くの人が反対票を投じない限り、この回答を削除した方がよいでしょう。この解決策は間違いなく間違っています。それは機能しますが、悪いプログラミングです。RecyclerViewのいくつかのブログを読んで、いくつかのアダプターライブラリを調べてください。FlexitAdapter、FastAdapterなど、Githubにはすでに多くの有効なものがあります...
Davideas

1
あなたの回答は、投票数の多い回答の長いリストの比較的新しいものであり、ページの下部にあるため、投票数はまだ0のままです。ちなみに、新しいコードではを使用する必要がありますgetAdapterPosition()
Davideas

2つのメソッドの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()。なぜなら、onBindViewHolder(...)は、notify()メソッドの後に呼び出されないためです。そのため、状況によってはクリック位置が間違っている可能性があります。
Alex Kisel 2017

内部にクリックリスナーを作成する必要がありますonCreateViewHolder
EpicPandaForce

2

あなたmainViewrowLayout(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();
                }
            });

そして私に知らせてください、あなたはこの解決策について何か質問がありますか?


onCreateViewHolderパフォーマンスを向上させるためにonClickListenerを設定する必要がありますが、次に使用する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が正確な結果を得ることができます..................
ディリープクリシュナンを

問題は、「RecyclerViewにonItemClickListener()がないのなぜですか?」 「RecyclerViewにonItemClickListener()を実装する方法」ではありません。。
Shashanth 2017年

0

PlaceHolderViewを使用する

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

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

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

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

0

Androidリサイクラービューアイテムのクリックイベントを処理するライブラリを作成しました。チュートリアル全体はhttps://github.com/ChathuraHettiarachchi/RecycleClickにあります

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

または使用できる長押しアイテムを処理するには

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

私はあなたのライブラリを試しましたが、Mavenの問題に直面していますか?
Abhijeet

0

recyclerviewアニメーションはテストされていません。もう1つは正常です。最大限に最適化されていると思います。インターフェイスには他の用途があり、一時的に無視できます。

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

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

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

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

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


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

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

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

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

}

これはインターフェースです

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

    void onItemClick(DATA1 data1, DATA2 data2);

    boolean onItemLongClick(DATA1 data1, DATA2 data2);
}

これは抽象クラスです

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

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

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

必要なのは

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

        }

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

BaseViewHolderがRecyclerView.ViewHolderとして
user8944115

R.id.tag_view_clickでは、valuesディレクトリで宣言する必要があります<item type = "id" name = "tag_view_click" />
user8944115 '16

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