如何在回收视图中选择位置?

我正在试验支持图书馆的回收视图和卡片。我有一张回收卡片的清单。每张卡片的右上角都有一个“ 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_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/taskDesc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:textSize="40sp"
android:text="hi"/>
<ImageView
android:id="@+id/xImg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:src="@drawable/ic_remove"/>
</RelativeLayout>
</android.support.v7.widget.CardView>

我试图用 TaskAdapter.javanotifyItemRemoved(position)中使用的位置标记该行:

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.访问适配器

216787 次浏览

onClickListener设置在 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)
}

补充@tyczj 回答:

通用适配器 Pseido 代码:

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


}

观众:

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


}






}

另一种方法-使用 View 类的 SetTag ()GetTag ()方法。

  1. 在适配器的 onBindViewHolder 方法中使用 SetTag ()

    @Override
    public void onBindViewHolder(myViewHolder viewHolder, int position) {
    viewHolder.mCardView.setTag(position);
    }
    

    在 myViewHolder 类中定义 mCardView

    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);
    }
    }
    
  2. use getTag() in your OnClickListener implementation

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

see https://stackoverflow.com/a/33027953/4658957 for more details

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

我就是这么解决的

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

获得焦点子,并使用它获得适配器的位置。

mRecyclerView.getChildAdapterPosition(mRecyclerView.getFocusedChild())

我认为获得物品位置最正确的方法是

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

因为视图,您并不总是单击行布局的根视图。如果 view 不是根目录(例如按钮) ,则会得到类强制转换异常。因此,首先我们需要找到视图,它是您 reciclerview 的直接子代。然后,使用回收视图 getChildAdapterposition (视图)查找位置;

就我个人而言,我发现的最简单的方法,并且对我很有效,如下所示:

在你的“回收适配器”类(子类)中创建一个接口

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

对我来说就是这样。 :)

不需要让 ViewHolder 实现 View.OnClickListener。您可以通过设置回收视图的 onCreateViewHolder 方法中的 click 侦听器来直接获得单击的位置。Adapter 这里是一个代码示例:

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


}

1. 创建类 Name 召回 TouchListener.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. 呼叫回收触摸监听器

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


}
}));

每个条目都要调用 onBindViewHolder () ,如果可以在 ViewHolder 构造函数中调用一次,那么在 onBindVieHolder ()中设置单击侦听器是一个不必要的重复选项。

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();
}
}
@Override
public void onClick(View v) {
int pos = getAdapterPosition();
}

就这么简单,在 ViewHolder

当使用数据绑定时,您需要知道一个项目的单击监听器中的回收视图单击位置:

科特林

    val recyclerView = view.parent as RecyclerView
val position = recyclerView.getChildAdapterPosition(view)