获取点击的项目及其在RecyclerView中的位置


104

我将其替换ListViewRecyclerView,列表显示正常,但我想知道如何获取被单击的项目及其位置,类似于OnItemClickListener.onItemClick(AdapterView parent, View v, int position, long id)我们在中使用的方法ListView

感谢您的想法!




对我来说最简单的方法:CustomSelectionCallback
ATES

Answers:


177

基于链接:为什么RecyclerView没有onItemClickListener()?RecyclerView与Listview有何不同?,还有@Duncan的一般想法,我在这里给出解决方案:

  • 定义一个接口,RecyclerViewClickListener用于将消息从适配器传递到Activity/ 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()


21
使用getLayoutPosition()方法,因为现在描述了getPosition()。
Ankur Chaudhary 2015年

2
感谢这段代码:)提示:private static RecyclerViewClickListener itemListener;在构造函数中以静态方式引用static 。
David Artmann

1
@khurramengr我最终在该方法的每个项目中添加了一个侦听器onBindViewHolder。此外,我的列表项并非全部可点击(仅部分项)。
Ferran Negre

1
您不应该在这里使用WeakReference new MyRecyclerViewAdapter(context, this)吗?这可能会导致内存泄漏
RamwiseMatt

2
public void recyclerViewListClicked(View v, int position);该修饰符public对于界面方法来说是多余的
Joel Raju

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()是我需要的。
阿亚兹

1
感谢代码人!!拯救了我的一天。我不确定将getAdapterPosition()放在哪里,然后按照您的代码让它工作...好又容易:)
Vinay 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

1
单击的视图位置。不是自定义方法。
吉尔伯托·伊瓦拉

这似乎是最干净的方法,尤其是因为您几乎总是对使用该位置获取数据感兴趣,并且可能无法访问RecyclerView对象。
FrostRocket

非常感谢int position = getAdapterPosition();
Shylendra Madda '17

请注意,在更新列表时调用getAdapterPosition(例如由于调用notififyXYZ)将返回-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类,您应该提供正在使用的库或类本身。
格雷格

@格雷格thanx !! 我忘了发贴!
MazRoid18年

5

如果您想从活动/片段而不是适配器中获取回收视图的Click事件,那么您也可以使用以下快捷方式。

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 '16

您可以仅通过适配器在TAG中设置项目的位置,然后如上所述获得标签txtStatusChange.getTag()。toString()
Amandeep Rohila

@AmandeepRohila为了使代码正常工作,我必须首先滚动到水平recyclerview的末尾。只有这样,吐司才能起作用。有没有一种方法可以使它工作而不必先滚动和返回?
iOSAndroidWindowsMo​​bileAppsDev

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

这是什么法术?完美运作。
Bolling

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上设置了一个标签,其中包含处理点击(例如位置)和clicklistener所需的信息


3
是的,我们可以在ViewHolder中设置单击侦听器,但是我需要将单击的项目视图和位置传递回我的片段以进行进一步处理
Xcihnegn 2015年

1

这是找到被单击项位置的最简单方法:

我也遇到了同样的问题。

我想找到RecyclerView()的单击/选定项目的位置,然后对该特定项目执行一些特定操作。

getAdapterPosition()方法的作用类似于这些东西。经过一天的长时间研究和尝试了许多其他方法之后,我发现了这种方法。

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的Adapter位置。

乐于帮助。随时提出疑问。


什么是最简单,最简单的方法来获得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();
    }

在Adapter
onClickLictener中onBindViewHolder 中的项目

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

现在,无论何时您在RecyclerView中更改位置,它都将保留在Holder中(或者也许应将其称为Listener)

我希望它会有用

我的第一篇文章


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

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方法在“活动”中应是什么样?我试图将商品的位置传递给Intent(以打开下一个活动),但我一直得到错误的位置。
AJW

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!虽然链接是共享知识的好方法,但将来如果链接断开,它们将无法真正回答问题。在回答中添加回答问题的链接的基本内容。如果内容太复杂或太大而无法容纳在此处,请描述所提出解决方案的总体思路。请记住,始终保留指向原始解决方案网站的链接参考。请参阅:我如何写一个好的答案?
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用户来说,它的作用将大得多,尤其是对于已经接受了答案的问题。请参阅:如何写一个好的答案
大卫·巴克

0

经过大量的试验和错误后,我发现有一种非常简单的方法可以执行此操作,即通过在适配器类中创建接口并在片段中实现该接口,现在出现了问题,我实例化了我的覆盖函数中的视图模型。现在,您可以将数据从该函数发送到viemodel以及从那里发送到任何地方。

我不知道此方法是否是好的编码方法,但是请在注释中让我知道,是否有任何想在注释部分中让我知道的信息,我会定期打开stackover流。


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为您的活动名称。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.