RecyclerViewでクリックされたアイテムとその位置を取得する


105

私はでリストをok に置き換えてListViewRecyclerViewますが、OnItemClickListener.onItemClick(AdapterView parent, View v, int position, long id)で使用する方法と同様に、クリックされたアイテムとその位置を取得する方法を知りたいのListViewですが。

アイデアをありがとう!




私にとって最も簡単な方法:CustomSelectionCallback
ATES

回答:


177

リンクに基づく:RecyclerViewにonItemClickListener()がないのはなぜですか?そしてRecyclerViewはListviewとどう違うのですか?、そして@Duncanの一般的な考えも、私はここに私の解決策を与えます:

  • RecyclerViewClickListenerアダプターからActivity/にメッセージを渡すためのインターフェースを1つ定義しますFragment

    public interface RecyclerViewClickListener {
        public void recyclerViewListClicked(View v, int position);
    }
    
  • ではActivity/ Fragmentインタフェースを実装し、またアダプタにリスナーを渡します。

    @Override
    public void recyclerViewListClicked(View v, int position){... ...}
    
    //set up adapter and pass clicked listener this
    myAdapter = new MyRecyclerViewAdapter(context, this);
    
  • AdapterViewHolder

    public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ItemViewHolder> {
       ... ... 
       private Context context;
       private static RecyclerViewClickListener itemListener;
    
    
       public MyRecyclerViewAdapter(Context context, RecyclerViewClickListener itemListener) {
           this.context = context;
           this.itemListener = itemListener;
           ... ...
       }
    
    
       //ViewHolder class implement OnClickListener, 
       //set clicklistener to itemView and, 
       //send message back to Activity/Fragment 
       public static class ItemViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
           ... ...
           public ItemViewHolder(View convertView) {
               super(convertView);
               ... ...
               convertView.setOnClickListener(this);
           }
    
           @Override
           public void onClick(View v) {
               itemListener.recyclerViewListClicked(v, this.getPosition());     
    
           }
       }
    }
    

テスト後、正常に動作します。


[ 更新 ]

API 22以降RecyclerView.ViewHoler.getPosition()は非推奨となったため、代わりにを使用しgetLayoutPosition()ます。


22
現在getPosition()が廃止されているため、getLayoutPosition()メソッドを使用します。
Ankur Chaudhary

2
このコードに感謝します:)ただ1つのヒント:private static RecyclerViewClickListener itemListener;コンストラクターで静的な方法で静的を参照します。
David Artmann、2015年

1
@khurramengrメソッドの各項目にリスナーを追加してしまいましたonBindViewHolder。さらに、私のリストアイテムはすべてクリック可能ではありませんでした(アイテムの一部のみ)。
Ferran Negre 2016年

1
ここでWeakReferenceを使用しないでください:new MyRecyclerViewAdapter(context, this)?これによりメモリリークが発生する可能性があります
RamwiseMatt 2017

2
public void recyclerViewListClicked(View v, int position);修飾子publicはインターフェースメソッドに冗長です
Joel Raju 2017年

35
public class MyRvAdapter extends RecyclerView.Adapter<MyRvAdapter.MyViewHolder>{
    public Context context;
    public ArrayList<RvDataItem> dataItems;

    ...
    constructor
    overrides
    ...

    class MyViewHolder extends RecyclerView.ViewHolder{
        public TextView textView;
        public Context context;

        public MyViewHolder(View itemView, Context context) {
            super(itemView);

            this.context = context;

            this.textView = (TextView)itemView.findViewById(R.id.textView);

            // on item click
            itemView.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View v) {
                    // get position
                    int pos = getAdapterPosition();

                    // check if item still exists
                    if(pos != RecyclerView.NO_POSITION){
                        RvDataItem clickedDataItem = dataItems.get(pos);
                        Toast.makeText(v.getContext(), "You clicked " + clickedDataItem.getName(), Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }
}

4
ありがとうございました。getAdapterPosition()が必要です。
Ayaz Alifov 2017年

1
コードマンをありがとう!私の日を救った。私はどこgetAdapterPositionを(置く)とあなたのコードを以下の私は...ニースと簡単:)作業それを得たことを確認しなかった
ビナイVissh

本当にありがとう、あなたのコードはまさに私がそれを必要としていました!幸せな男
Naveen Nirban Yadav

13

クリックリスナーを設定する例を次に示します。

Adapter extends  RecyclerView.Adapter<MessageAdapter.MessageViewHolder> {  ...  }

 public static class MessageViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public TextView     tv_msg;
        public TextView     tv_date;
        public TextView     tv_sendTime;
        public ImageView    sharedFile;
        public ProgressBar sendingProgressBar;

        public MessageViewHolder(View v) {
            super(v);
            tv_msg =  (TextView) v.findViewById(R.id.tv_msg);
            tv_date = (TextView)  v.findViewById(R.id.tv_date);
            tv_sendTime = (TextView)  v.findViewById(R.id.tv_sendTime);
            sendingProgressBar = (ProgressBar) v.findViewById(R.id.sendingProgressBar);
            sharedFile = (ImageView) v.findViewById(R.id.sharedFile);

            sharedFile.setOnClickListener(this);

        }

        @Override
        public void onClick(View view) {
        int position  =   getAdapterPosition();


            switch (view.getId()){
                case R.id.sharedFile:


                    Log.w("", "Selected"+position);


                    break;
            }
        }

    }

getAdapterPostion();とは ここに?
TheDevMan 2015

1
クリックされたビューの位置。カスタムメソッドではありません。
Gilberto Ibarra 2015

これは、特に位置を使用してデータを取得することにほとんど関心があり、RecyclerViewオブジェクトにアクセスできない可能性があるため、これを行う最もクリーンな方法のようです。
FrostRocket 2016

int position = getAdapterPosition();
どうも

たとえばnotififyXYZを呼び出したために、リストの更新中にgetAdapterPositionを呼び出すと、-1が返されることに注意してください
David

11

このコードを、アクティビティのリサイクラービューを定義する場所に配置します。

    rv_list.addOnItemTouchListener(
            new RecyclerItemClickListener(activity, new RecyclerItemClickListener.OnItemClickListener() {
                @Override
                public void onItemClick(View v, int position) {

                    Toast.makeText(activity, "" + position, Toast.LENGTH_SHORT).show();
                }
            })
    );

次に、別のクラスを作成し、このコードを配置します。

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {

    private OnItemClickListener mListener;
    public interface OnItemClickListener {
        public void onItemClick(View view, int position);
    }
    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) {

    }
}

7

以下のコードでJavaファイルを作成します

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.getChildLayoutPosition(childView));
        return true;
    }
    return false;
}

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

@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

}

RecyclerViewオブジェクトのリスナーを使用するだけです。

recyclerView.addOnItemTouchListener(  
new RecyclerItemClickListener(context, new RecyclerItemClickListener.OnItemClickListener() {
  @Override public void onItemClick(View view, int position) {
    // TODO Handle item click
  }
}));

RecyclerItemClickListenerはデフォルトのandroidクラスではありません。使用しているライブラリまたはクラス自体を提供する必要があります。
グレッグ

@グレッグサンクス!! 投稿するのを忘れました!
MazRoid 2018

5

アダプターの代わりにアクティビティ/フラグメントからのリサイクルビューのクリックイベントが必要な場合は、次のショートカット方法を使用することもできます。

recyclerView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                final TextView txtStatusChange = (TextView)v.findViewById(R.id.txt_key_status);
                txtStatusChange.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        Log.e(TAG, "hello text " + txtStatusChange.getText().toString() + " TAG " + txtStatusChange.getTag().toString());
                        Util.showToast(CampaignLiveActivity.this,"hello");
                    }
                });
                return false;
            }
        });

インターフェイスを使用するなど、他の長い方法を使用することもできます


、こんにちは、でもクリックしたアイテムの位置を取得する必要がある場合はどうでしょうか。?
mfaisalhyder 2016年

アダプターを介してTAG内のアイテムの位置を設定し、上記のようにタグを取得することができます。txtStatusChange.getTag()。toString()
Amandeep

@AmandeepRohilaコードが機能するためには、まず水平リサイクラービューの最後までスクロールする必要があります。その後、トーストが機能します。最初に前後にスクロールせずに機能させる方法はありませんか?
iOSAndroidWindowsMo​​bileAppsDev 2016年

4
recyclerViewObject.addOnItemTouchListener(
    new RecyclerItemClickListener(
        getContext(),
        recyclerViewObject,
        new RecyclerItemClickListener.OnItemClickListener() {
            @Override public void onItemClick(View view, int position) {
                // view is the clicked view (the one you wanted
                // position is its position in the adapter
            }
            @Override public void onLongItemClick(View view, int position) {
            }
        }
    )
);

これはどんな魔術ですか?完璧に動作します。
ボリング

2

以下のコードを使用してください:

public class SergejAdapter extends RecyclerView.Adapter<SergejAdapter.MyViewHolder>{

...

class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{


    @Override
    public void onClick(View v) {
        // here you use position
        int position = getAdapterPosition();
        ...

    }
}
}

1

RecyclerViewはそのようなメソッドを提供していません。

RecyclerViewでクリックイベントを管理するために、ViewHolderをバインドするときに、アダプターにonClickListenerを実装することになりました。ViewHolderでは、(ImageViews、TextViewsなどでできるように)ルートビューへの参照を保持し、バインドするときにviewHolderクリックを処理するために必要な情報(位置など)とクリックリスナーをタグに設定しました


3
はい、ViewHolderでクリックリスナーを設定できますが、クリックしたアイテムのビューと位置をフラグメントに
戻し

1

クリックされたアイテムの位置を見つける最も簡単で簡単な方法は次のとおりです。

私も同じ問題に直面しました。

RecyclerView()のクリック/選択されたアイテムの位置を見つけて、その特定のアイテムに対して特定の操作を実行したいと思っていました。

getAdapterPosition()メソッドは、この種のものの魅力のように機能します。この方法は、1日の長い研究の結果、他の多くの方法を試した後で見つかりました。

int position = getAdapterPosition();
Toast.makeText(this, "Position is: "+position, Toast.LENGTH_SHORT).show();

追加のメソッドを使用する必要はありません。'position'という名前のグローバル変数を作成し、アダプターの主要なメソッド(クラスなど)のいずれかでgetAdapterPosition()を使用して初期化するだけです。

このリンクからの簡単なドキュメントを次に示します。

バージョン22.1.0で追加されたgetAdapterPosition int getAdapterPosition()このViewHolderによって表されるアイテムのアダプタの位置を返します。保留中のアダプターの更新はあるが、新しいレイアウトパスがまだ行われていない場合、これはgetLayoutPosition()とは異なる場合があることに注意してください。RecyclerViewは、次のレイアウトトラバーサルまでアダプタの更新を処理しません。これにより、ユーザーが画面に表示するものとアダプタの内容との間に一時的な不整合が生じる可能性があります。この不整合は16ms未満になるため重要ではありませんが、ViewHolder位置を使用してアダプターにアクセスする場合は問題になる可能性があります。場合によっては、ユーザーイベントに応じてアクションを実行するために、アダプターの正確な位置を取得する必要があります。その場合、ViewHolderのアダプタ位置を計算するこのメソッドを使用する必要があります。

お力になれて、嬉しいです。ご不明な点はお気軽にお問い合わせください。


RecyclerViewのクリックされたアイテムの値を取得する最も簡単で簡単な方法は何ですか?
अक्षयपरूळेकर

1

私の簡単な解決策

Make a position holder:

    public class PositionHolder {

    private int position;

    public PositionHolder(int position) {
        this.position = position;
    }

    public int getPosition() {
        return position;
    }

    public void setPosition(int position) {
        this.position = position;
    }
}

アクティビティから取得する必要があるデータを配置または配置するだけです。

アダプターコンストラクター:

public ItemsAdapter(Context context, List<Item> items, PositionHolder positionHolder){
        this.context = context;
        this.items = items;
        this.positionHolder = positionHolder;
}

活動中:

 @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        selectedPosition = 0;

        positionHolder = new PositionHolder(selectedPosition);
        initView();
    }

onBindViewHolderの項目のアダプタ
onClickLictener

holder.holderButton.setOnClickListener(v -> {
            positionHolder.setPosition(position);
            notifyDataSetChanged();
        });

これで、RecyclerViewで位置を変更するたびに、ホルダーに保持されます(または、リスナーと呼ばれる必要があります)

お役に立てれば幸いです

私の最初の投稿; P


0
//Create below methods into the Activity which contains RecyclerView.


private void createRecyclerView() {

final RecyclerView recyclerView = (RecyclerView)findViewById(R.id.recyclerView);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    MyAdapter myAdapter=new MyAdapter(dataAray,MianActivity.this);
    recyclerView.setAdapter(myAdapter);
    recyclerView.setItemAnimator(new DefaultItemAnimator());

    setRecyclerViewClickListner(recyclerView);
}

private void setRecyclerViewClickListner(RecyclerView recyclerView){

    final GestureDetector gestureDetector = new GestureDetector(MainActivity.this,new GestureDetector.SimpleOnGestureListener() {
        @Override public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }
    });


    recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
        @Override
        public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
            View child =recyclerView.findChildViewUnder(motionEvent.getX(),motionEvent.getY());
            if(child!=null && gestureDetector.onTouchEvent(motionEvent)){
               int position=recyclerView.getChildLayoutPosition(child);
                String name=itemArray.get(position).name;

            return true;
        }

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

        }

        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean b) {

        }
    });
}

3
説明を追加してください。導入せずにコードをダンプするだけで、問題がどのように修正されるかについての説明はあまり役に立ちません。
Mark Rotteveel、2015

0

このようにしてみてください

アダプタークラス:

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

public interface OnItemClickListener {
    void onItemClick(ContentItem item);
}

private final List<ContentItem> items;
private final OnItemClickListener listener;

public ContentAdapter(List<ContentItem> items, OnItemClickListener listener) {
    this.items = items;
    this.listener = listener;
}

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

@Override public void onBindViewHolder(ViewHolder holder, int position) {
    holder.bind(items.get(position), listener);
}

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

static class ViewHolder extends RecyclerView.ViewHolder {

    private TextView name;
    private ImageView image;

    public ViewHolder(View itemView) {
        super(itemView);
        name = (TextView) itemView.findViewById(R.id.name);
        image = (ImageView) itemView.findViewById(R.id.image);
    }

    public void bind(final ContentItem item, final OnItemClickListener listener) {
        name.setText(item.name);
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override public void onClick(View v) {
                listener.onItemClick(item);
            }
        });
    }
}

}

あなたの活動またはフラグメントで:

ContentAdapter adapter = new ContentAdapter(itemList, this);

注:アクティビティまたはフラグメントで指定したコンテキストに基づいてOnItemClickListenerを実装し、メソッドをオーバーライドします。


上記の素晴らしい解決策。上記に追加して、アクティビティでのonItemClickメソッドの外観を示すことができますか?(次のアクティビティを開くために)アイテムの位置をインテントに渡そうとしていますが、間違った位置を取得し続けています。
AJW 2017

0

いつも別のアプローチを使用しています。人々は、ViewHolderによって表示されるオブジェクトへの参照を保存するのではなく、ビューの位置を保存または取得するようです。

代わりにこのアプローチを使用し、onBindViewHolder()が呼び出されたときにViewHolderに格納し、onViewRecycled()で参照をnullに設定します。

ViewHolderが非表示になるたびに、リサイクルされます。したがって、これは大量のメモリ消費には影響しません。

@Override
public void onBindViewHolder(final ItemViewHolder holder, int position) {
    ...
    holder.displayedItem = adapterItemsList.get(i);
    ...
}

@Override
public void onViewRecycled(ItemViewHolder holder) {
    ...
    holder.displayedItem = null;
    ...
}

class ItemViewHolder extends RecyclerView.ViewHolder {
    ...
    MySuperItemObject displayedItem = null;
    ...
}

0

Kotlin
メソッドの短い拡張は、すべてのアイテムの絶対位置を返します(表示されているアイテムのみの位置ではありません)。

fun RecyclerView.getChildPositionAt(x: Float, y: Float): Int {
    return getChildAdapterPosition(findChildViewUnder(x, y))
}

そして使い方

val position = recyclerView.getChildPositionAt(event.x, event.y)

0

カスタムインターフェイスのjavaメソッドでgetLayoutPosition()を使用します。これにより、アイテムの選択した位置が返されます。詳細を確認してください

https://becody.com/get-clicked-item-and-its-position-in-recyclerview/


1
Stack Overflowへようこそ!リンクは知識を共有するための優れた方法ですが、将来リンクが壊れたとしても、質問に答えることはできません。質問に回答するリンクの重要なコンテンツを回答に追加します。コンテンツが複雑すぎて大きすぎてここに収まらない場合は、提案されたソリューションの一般的なアイデアを説明してください。元のソリューションのWebサイトへのリンク参照を常に保持することを忘れないでください。参照:良い回答を書くにはどうすればよいですか?
sɐunıɔןɐqɐp

0

デザイナーから、onClicklistItem のプロパティを単一のパラメーターで定義されたメソッドに設定できます。以下に定義されているメソッドの例があります。getAdapterPositionメソッドは、選択されたlistItemのインデックスを提供します。

public void exampleOnClickMethod(View view){
    myRecyclerView.getChildViewHolder(view).getAdapterPosition());
}

RecyclerViewのセットアップについては、こちらのドキュメントを参照してください:https : //developer.android.com/guide/topics/ui/layout/recyclerview


0
//simply check if the adapter position you get not less than zero

holder.btnDelItem.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if(holder.getAdapterPosition()>=0){
            list.remove(holder.getAdapterPosition());
            notifyDataSetChanged();
        }
    }
});

3
古い質問に回答するとき、回答がどのように役立つかを説明するコンテキストを含めれば、回答は他のStackOverflowユーザーにとって非常に役立ちます。特に、既に回答が受け入れられている質問の場合はそうです。参照:良い回答を書くにはどうすればよいですか
David Buck

0

多くの試行錯誤の後、これを行う非常に簡単な方法があることを発見しました。これは、アダプタークラスでインターフェイスを作成し、それをフラグメントで実装することです。ここでひねりが加えられ、オーバーライド関数内のビューモデルをインスタンス化しました。フラグメントを使用して、その関数からデータをviemodelに送信し、そこからどこにでも送信できます。

この方法が適切なコーディング方法であるかどうかはわかりませんが、コメントで教えてください。コメント欄で教えてほしい場合は、スタックオーバーフローを定期的に開いています。


0
recyclerView.addOnItemTouchListener(object : AdapterView.OnItemClickListener,
                RecyclerView.OnItemTouchListener {
                override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
                    TODO("Not yet implemented")
                }

                override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
                    TODO("Not yet implemented")
                }

                override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
                    TODO("Not yet implemented")
                }

                override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
                    TODO("Not yet implemented")
                }

            })

Kotlinを使用する場合


このコードは問題を解決する可能性がありますが、これが問題を解決する方法と理由の説明含めると、投稿の品質が向上し、投票数が増える可能性があります。あなたが今尋ねている人だけでなく、将来の読者のための質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提を示してください。
БогданОпир

-4

onViewHolderでonClickListinerを任意のビューに設定し、サイドクリックで次のコードを使用します。

Toast.makeText(Drawer_bar.this、 "position" + position、Toast.LENGTH_SHORT).show();

Drawer_Barアクティビティ名に置き換えます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.