繁体   English   中英

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

[英]Get clicked item and its position in RecyclerView

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

感谢您的想法!

基于链接: 为什么 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.ViewHolder.getPosition()已被弃用,因此使用getLayoutPosition()代替。

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

这是设置单击侦听器的示例。

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

    }

将此代码放在您在活动中定义回收器视图的位置。

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

    }
}

使用以下代码创建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
  }
}));

如果您想要来自活动/片段而不是适配器的回收视图的 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;
            }
        });

您还可以使用其他长的方式,如使用界面

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

使用以下代码:-

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

    }
}
}

这是查找被点击项目位置的最简单和最简单的方法:

我也遇到过同样的问题。

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

getAdapterPosition() 方法对于这些东西来说就像一个魅力。 经过一天的长期研究并尝试了许多其他方法后,我找到了这种方法。

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

您不必使用任何额外的方法。 只需创建一个名为“position”的全局变量,并在适配器的任何主要方法(类或类似方法)中使用 getAdapterPosition() 对其进行初始化。

这是来自此链接的简要文档。

22.1.0 版本新增 getAdapterPosition int getAdapterPosition() 返回此 ViewHolder 所代表的 item 的 Adapter 位置。 请注意,如果存在挂起的适配器更新但尚未发生新的布局传递,则这可能与 getLayoutPosition() 不同。 RecyclerView 在下一次布局遍历之前不处理任何适配器更新。 这可能会在用户在屏幕上看到的内容与适配器内容具有的内容之间造成暂时的不一致。 这种不一致并不重要,因为它会小于 16 毫秒,但如果您想使用 ViewHolder 位置来访问适配器,则可能会出现问题。 有时,您可能需要获取确切的适配器位置来执行某些操作以响应用户事件。 在这种情况下,您应该使用此方法来计算 ViewHolder 的适配器位置。

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

我的简单解决方案

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)

我希望它会很有用

我的第一篇文章;P

RecyclerView 不提供这种方法。

为了管理 RecyclerView 上的点击事件,我最终在我的适配器中实现了 onClickListener,当绑定 ViewHolder 时:在我的 ViewHolder 中,我保留对根视图的引用(就像你可以使用你的 ImageViews、TextViews 等......)和绑定时我在 viewHolder 上设置了一个标签,其中包含我需要处理点击(例如位置)和点击侦听器的信息

每次我使用另一种方法。 人们似乎在视图上存储或获取位置,而不是存储对 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;
    ...
}

在设计器中,您可以将 listItem 的onClick属性设置为使用单个参数定义的方法。 我有一个下面定义的示例方法。 getAdapterPosition 方法将为您提供所选列表项的索引。

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

有关设置 RecyclerView 的信息,请参阅此处的文档: https : //developer.android.com/guide/topics/ui/layout/recyclerview

简单(但不是那么明显)的解决方案是这样做:

@Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {

        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.recycler_row, viewGroup, false);
        ViewHolder vh = new ViewHolder(v);

然后,无论何时,调用方法currentPosition = vh.getLayoutPosition();

在我的情况下,我在一个 onClick 监听器中执行该操作,该监听器放置在该 vh 视图上。 恕我直言,recycleView 类错过了 .getPosition() 和我们从 ListView 知道的其他功能,有时是强制性的,根本不可用。 我非常后悔从 ListView 转移到 Recycle 同上。 时间窃贼花费了一天多的时间来揭开它的神秘面纱。 糟糕的工程。 (但有什么就可以了)

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

        }
    });
}

用这种方法试试

适配器类:

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

}

在您的 Activity 或片段中:

ContentAdapter adapter = new ContentAdapter(itemList, this);

注意:根据您在活动或片段和覆盖方法中提供的上下文实现 OnItemClickListener。

Kotlin 的简短扩展
方法返回所有项目的绝对位置(不是仅可见项目的位置)。

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

和用法

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

在您的自定义接口 java 方法中使用 getLayoutPosition()。 这将返回一个项目的选定位置,检查完整的细节

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

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

经过大量的反复试验,我发现有一种非常简单的方法可以做到这一点,即通过在适配器类中创建一个接口并在片段中实现它,现在出现了转折,我在我的覆盖函数中实例化了视图模型。片段现在您可以将数据从该函数发送到 viemodel 并从那里发送到任何地方。

我不知道这种方法是否是好的编码方法,但请在评论中告诉我,如果有人想在评论部分看到让我知道,我会定期打开 stackover 流程​​。

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

在 onViewHolder 中将 onClickListiner 设置为任何视图,并在侧点击中使用以下代码:

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

Drawer_Bar替换为您的活动名称。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM