如何在 RecyclerView 中选择位置?
Posted
技术标签:
【中文标题】如何在 RecyclerView 中选择位置?【英文标题】:How do I get the position selected in a RecyclerView? 【发布时间】:2014-12-28 05:20:21 【问题描述】:我正在试验支持库的 recyclerview 和卡片。我有卡片的recyclerview。每张卡片的右上角都有一个“x”图标,可将其移除:
卡片xml,list_item.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_
android:layout_margin="5dp">
<RelativeLayout
android:layout_
android:layout_>
<TextView
android:id="@+id/taskDesc"
android:layout_
android:layout_
android:layout_alignParentBottom="true"
android:textSize="40sp"
android:text="hi"/>
<ImageView
android:id="@+id/xImg"
android:layout_
android:layout_
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:src="@drawable/ic_remove"/>
</RelativeLayout>
</android.support.v7.widget.CardView>
我试图用notifyItemRemoved(position)
中TaskAdapter.java
中的位置标记该行:
public class TaskAdapter extends RecyclerView.Adapter<TaskAdapter.TaskViewHolder>
private List<Task> taskList;
private TaskAdapter thisAdapter = this;
// cache of views to reduce number of findViewById calls
public static class TaskViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
protected TextView taskTV;
protected ImageView closeBtn;
public TaskViewHolder(View v)
super(v);
taskTV = (TextView)v.findViewById(R.id.taskDesc);
@Override
public void onClick(View v)
int position = v.getTag();
adapter.notifyItemRemoved(position);
public TaskAdapter(List<Task> tasks)
if(tasks == null)
throw new IllegalArgumentException("tasks cannot be null");
taskList = tasks;
// onBindViewHolder binds a model to a viewholder
@Override
public void onBindViewHolder(TaskViewHolder taskViewHolder, int pos)
final int position = pos;
Task currTask = taskList.get(pos);
taskViewHolder.taskTV.setText(currTask.getDescription());
taskViewHolder.closeBtn.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
thisAdapter.notifyItemRemoved(position);
);
@Override
public int getItemCount()
return taskList.size();
// inflates row to create a viewHolder
@Override
public TaskViewHolder onCreateViewHolder(ViewGroup parent, int pos)
View itemView = LayoutInflater.from(parent.getContext()).
inflate(R.layout.list_item, parent, false);
return new TaskViewHolder(itemView);
这不起作用,因为您无法设置标签,也无法从onClick.
访问适配器
【问题讨论】:
【参考方案1】:将您的onClickListener
s 设置为onBindViewHolder()
,您就可以从那里访问该职位。如果您将它们设置在您的ViewHolder
中,您将不知道点击了哪个位置,除非您还将该位置传递给ViewHolder
编辑
正如pskink
指出的ViewHolder
有一个getPosition()
,所以你最初的做法是正确的。
点击视图时,您可以在ViewHolder
中使用getPosition()
并返回位置
更新
getPosition()
现已弃用并替换为 getAdapterPosition()
2020 年更新
getAdapterPosition()
现在已弃用并替换为 getAbsoluteAdapterPosition()
或 getBindingAdapterPosition()
Kotlin 代码:
override fun onBindViewHolder(holder: MyHolder, position: Int)
// - get element from your dataset at this position
val item = myDataset.get(holder.absoluteAdapterPosition)
【讨论】:
你能显示一些代码吗?如果 taskViewHolder 没有 setOnClickListener 方法,我该怎么做? 您使用那里的viewholder中的视图 @tyczj 不,更好的地方是在 ViewHolder ctor 中设置 listener,ViewHolder 知道自己的位置 @pskink 如果不将位置传递给构造函数,您将如何知道位置呢? @tyczj ViewHolder.getPosition(),顺便说一句,当你创建一个 ViewHolder 时你不知道位置,位置是在 onBindViewHolder 中设置的【参考方案2】:另一种方法 - 使用 View 类的 setTag() 和 getTag() 方法。
在适配器的 onBindViewHolder 方法中使用 setTag()
@Override
public void onBindViewHolder(myViewHolder viewHolder, int position)
viewHolder.mCardView.setTag(position);
mCardView 在 myViewHolder 类中定义
private class myViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
public View mCardView;
public myViewHolder(View view)
super(view);
mCardView = (CardView) view.findViewById(R.id.card_view);
mCardView.setOnClickListener(this);
在您的 OnClickListener 实现中使用 getTag()
@Override
public void onClick(View view)
int position = (int) view.getTag();
//display toast with position of cardview in recyclerview list upon click
Toast.makeText(view.getContext(),Integer.toString(position),Toast.LENGTH_SHORT).show();
查看https://***.com/a/33027953/4658957了解更多详情
【讨论】:
太棒了!简单而最好的【参考方案3】:补充@tyczj 答案:
通用适配器伪代码:
public abstract class GenericRecycleAdapter<T, K extends RecyclerView.ViewHolder> extends RecyclerView.Adapter
private List<T> mList;
//default implementation code
public abstract int getLayout();
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
View v = LayoutInflater.from(parent.getContext())
.inflate(getLayout(), parent, false);
return getCustomHolder(v);
public Holders.TextImageHolder getCustomHolder(View v)
return new Holders.TextImageHolder(v)
@Override
public void onClick(View v)
onItem(mList.get(this.getAdapterPosition()));
;
abstract void onItem(T t);
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
onSet(mList.get(position), (K) holder);
public abstract void onSet(T item, K holder);
ViewHolder:
public class Holders
public static class TextImageHolder extends RecyclerView.ViewHolder implements View.OnClickListener
public TextView text;
public TextImageHolder(View itemView)
super(itemView);
text = (TextView) itemView.findViewById(R.id.text);
text.setOnClickListener(this);
@Override
public void onClick(View v)
适配器使用:
public class CategoriesAdapter extends GenericRecycleAdapter<Category, Holders.TextImageHolder>
public CategoriesAdapter(List<Category> list, Context context)
super(list, context);
@Override
void onItem(Category category)
@Override
public int getLayout()
return R.layout.categories_row;
@Override
public void onSet(Category item, Holders.TextImageHolder holder)
【讨论】:
【参考方案4】: public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener
FrameLayout root;
public ViewHolder(View itemView)
super(itemView);
root = (FrameLayout) itemView.findViewById(R.id.root);
root.setOnClickListener(this);
@Override
public void onClick(View v)
LogUtils.errorLog("POS_CLICKED: ",""+getAdapterPosition());
【讨论】:
【参考方案5】:就我个人而言,我发现并且最适合我的最简单方法如下:
在“RecycleAdapter”类(子类)中创建一个接口
public interface ClickCallback
void onItemClick(int position);
在构造函数中添加接口的变量作为参数。
private String[] items;
private ClickCallback callback;
public RecyclerAdapter(String[] items, ClickCallback clickCallback)
this.items = items;
this.callback = clickCallback;
在 ViewHolder(另一个子类)中设置 Click 监听器,并通过接口传递“位置”
AwesomeViewHolder(View itemView)
super(itemView);
itemView.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
callback.onItemClick(getAdapterPosition());
);
mTextView = (TextView) itemView.findViewById(R.id.mTextView);
现在,在活动/片段中初始化回收器适配器时,只需创建一个新的“ClickCallback”(接口)
String[] values = "Hello","World";
RecyclerAdapter recyclerAdapter = new RecyclerAdapter(values, new RecyclerAdapter.ClickCallback()
@Override
public void onItemClick(int position)
// Do anything with the item position
);
对我来说就是这样。 :)
【讨论】:
【参考方案6】:我是这样解决的
class MyOnClickListener implements View.OnClickListener
@Override
public void onClick(View v)
int itemPosition = mRecyclerView.getChildAdapterPosition(v);
myResult = results.get(itemPosition);
在适配器中
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType)
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_wifi, parent, false);
v.setOnClickListener(new MyOnClickListener());
ViewHolder vh = new ViewHolder(v);
return vh;
【讨论】:
请详细说明你的答案,你在代码中做了什么。【参考方案7】:获得专注的孩子,并使用它来获得适配器中的位置。
mRecyclerView.getChildAdapterPosition(mRecyclerView.getFocusedChild())
【讨论】:
【参考方案8】:1.创建类名 RecyclerTouchListener.java
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener
private GestureDetector gestureDetector;
private ClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener)
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener()
@Override
public boolean onSingleTapUp(MotionEvent e)
return true;
@Override
public void onLongPress(MotionEvent e)
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null)
clickListener.onLongClick(child, recyclerView.getChildAdapterPosition(child));
);
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e))
clickListener.onClick(child, rv.getChildAdapterPosition(child));
return false;
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e)
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept)
public interface ClickListener
void onClick(View view, int position);
void onLongClick(View view, int position);
2。调用 RecyclerTouchListener
recycleView.addOnItemTouchListener(new RecyclerTouchListener(this, recycleView,
new RecyclerTouchListener.ClickListener()
@Override
public void onClick(View view, int position)
Toast.makeText(MainActivity.this,Integer.toString(position),Toast.LENGTH_SHORT).show();
@Override
public void onLongClick(View view, int position)
));
【讨论】:
【参考方案9】:我认为获取项目位置最正确的方法是
View.OnClickListener onClickListener = new View.OnClickListener()
@Override public void onClick(View v)
View view = v;
View parent = (View) v.getParent();
while (!(parent instanceof RecyclerView))
view=parent;
parent = (View) parent.getParent();
int position = recyclerView.getChildAdapterPosition(view);
因为视图,您单击的并不总是行布局的根视图。如果视图不是根视图(例如按钮),您将获得 Class cast 异常。因此,首先我们需要找到视图,它是您的 reciclerview 的直接孩子。然后,使用 recyclerView.getChildAdapterPosition(view); 找到位置;
【讨论】:
【参考方案10】:onBindViewHolder() 会为每个项目调用,并且在 onBindVieHolder() 中设置点击侦听器是不必要的重复选项,您可以在 ViewHolder 构造函数中调用一次。
public class MyViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener
public final TextView textView;
public MyViewHolder(View view)
textView = (TextView) view.findViewById(R.id.text_view);
view.setOnClickListener(this);
// getAdapterPosition() retrieves the position here.
@Override
public void onClick(View v)
// Clicked on item
Toast.makeText(mContext, "Clicked on position: " + getAdapterPosition(), Toast.LENGTH_SHORT).show();
【讨论】:
【参考方案11】:无需让您的 ViewHolder 实现 View.OnClickListener。您可以通过在 RecyclerView.Adapter 的 onCreateViewHolder 方法中设置点击监听器直接获取点击位置,这里是代码示例:
public class ItemListAdapterRecycler extends RecyclerView.Adapter<ItemViewHolder>
private final List<Item> items;
public ItemListAdapterRecycler(List<Item> items)
this.items = items;
@Override
public ItemViewHolder onCreateViewHolder(final ViewGroup parent, int viewType)
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_row, parent, false);
view.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View view)
int currentPosition = getClickedPosition(view);
Log.d("DEBUG", "" + currentPosition);
);
return new ItemViewHolder(view);
@Override
public void onBindViewHolder(ItemViewHolder itemViewHolder, int position)
...
@Override
public int getItemCount()
return items.size();
private int getClickedPosition(View clickedView)
RecyclerView recyclerView = (RecyclerView) clickedView.getParent();
ItemViewHolder currentViewHolder = (ItemViewHolder) recyclerView.getChildViewHolder(clickedView);
return currentViewHolder.getAdapterPosition();
【讨论】:
【参考方案12】:@Override
public void onClick(View v)
int pos = getAdapterPosition();
就这么简单,ViewHolder
【讨论】:
【参考方案13】:使用数据绑定时,您需要从项目的点击侦听器内部知道 RecyclerView 点击位置:
科特林
val recyclerView = view.parent as RecyclerView
val position = recyclerView.getChildAdapterPosition(view)
【讨论】:
以上是关于如何在 RecyclerView 中选择位置?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 RecyclerView 适配器中获取第二个模型的位置
如何使用Recyclerview中单击的适配器位置获取数据?
如何根据其在 onCreateViewHolder 方法中的位置在 RecyclerView 中膨胀不同的布局