如何在RecyclerView中获取所选位置?

时间:2014-10-31 19:41:38

标签: android android-support-library android-recyclerview android-cardview

我正在试验支持库的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_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>

我尝试使用我在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}}

访问适配器

13 个答案:

答案 0 :(得分:93)

onClickListener设置为onBindViewHolder(),您可以从那里访问该位置。如果您在ViewHolder中设置它们,除非您将该位置传递到ViewHolder

,否则您将无法知道点击的位置

修改

由于pskink指出ViewHolder有一个getPosition()所以你最初这样做的方式是正确的。

点击视图后,您可以在getPosition()中使用ViewHolder并返回位置

<强>更新

getPosition()现已弃用,已替换为getAdapterPosition()

Kotlin代码:

override fun onBindViewHolder(holder: MyHolder, position: Int) {
        // - get element from your dataset at this position
        val item = myDataset.get(holder.adapterPosition)
    }

答案 1 :(得分:14)

另一种方法 - 使用View类的 setTag() getTag()方法。

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

    public MyDbContext(string connectionString)
        : base(connectionString)
    {
        if (!Database.Exists())
        {
            Database.SetInitializer(new CreateInitializer());
        }
        else
        {
            bool isCompatible = false;
    
            isCompatible = Database.CompatibleWithModel(false);
    
    
            if (!isCompatible)
            {
                // Here is where it gets thrown.  
                throw new ExceptionDatabaseVersion("Data structure changed");
            }
        }
    }` 
    

    其中mCardView在myViewHolder类中定义

    @Override
    public void onBindViewHolder(myViewHolder viewHolder, int position) {
        viewHolder.mCardView.setTag(position);
    }
    
  2. 在OnClickListener实现中使用 getTag()

    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);
               }
           }
    
  3. 有关详细信息,请参阅https://stackoverflow.com/a/33027953/4658957

答案 2 :(得分:8)

补充@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);

}

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

    }



}

答案 3 :(得分:5)

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

答案 4 :(得分:3)

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

在“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侦听器并通过界面传递'position'

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

这对我来说。 :)

答案 5 :(得分:2)

我这样解决了

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

答案 6 :(得分:2)

获得专注的孩子,并用它来获得适配器中的位置。

mRecyclerView.getChildAdapterPosition(mRecyclerView.getFocusedChild())

答案 7 :(得分:1)

我认为获得项目位置的最正确方法是

.article {
    @-: ~'>'; 
    @{-}, *:not(.example) {
        h1 {color: red}
        h2 {color: blue}
    }
}

由于视图,您不一定要点击行布局的根视图。如果视图不是根视图(例如按钮),您将获得类强制转换异常。因此,首先我们需要找到视图,这是你reciclerview的直接孩子。然后,使用recyclerView.getChildAdapterPosition(view);

查找位置

答案 8 :(得分:1)

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 :(得分:0)

无需让ViewHolder实现View.OnClickListener。您可以通过在RecyclerView的方法onCreateViewHolder中设置单击侦听器来直接获取单击的位置.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();
    }

}

答案 10 :(得分:0)

每个项目都会调用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();
   }
}

答案 11 :(得分:0)

@Override
public void onClick(View v) {
     int pos = getAdapterPosition();
}

就这么简单,在ViewHolder

答案 12 :(得分:0)

使用数据绑定时,您需要从项目的点击侦听器内部了解RecyclerView点击位置:

科特琳

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