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

时间:2015-02-03 10:32:25

标签: android listview android-recyclerview recycler-adapter

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

感谢您的想法!

22 个答案:

答案 0 :(得分:157)

基于链接:Why doesn't RecyclerView have onItemClickListener()? and How RecyclerView is different from 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()

答案 1 :(得分:27)

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

答案 2 :(得分:13)

以下是设置Click Listener的示例。

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

    }

答案 3 :(得分: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) {

    }
}

答案 4 :(得分: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;
            }
        });

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

答案 5 :(得分: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) {
            }
        }
    )
);

答案 6 :(得分:3)

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

答案 7 :(得分:2)

我的简单解决方案

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

答案 8 :(得分: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();
        ...

    }
}
}

答案 9 :(得分:1)

RecyclerView不提供此类方法。

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

答案 10 :(得分:0)

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

@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 同上。时间窃贼花费了一天多的时间来揭开它的神秘面纱。糟糕的工程。 (不过有什么好)

答案 11 :(得分: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

答案 12 :(得分:0)

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

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

答案 13 :(得分: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();
        }
    }
});

答案 14 :(得分:0)

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

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

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

答案 15 :(得分:0)

在自定义接口java方法中使用getLayoutPosition()。这将返回项目的选定位置,请在

上查看详细信息

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

答案 16 :(得分:0)

  

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

我也遇到了同样的问题。

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

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

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

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

这是link的简要文档。

  

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

很乐意提供帮助。随时提出疑问。

答案 17 :(得分:0)

科特林的短扩展名
方法返回所有项目的绝对位置(而不是仅可见项目的位置)。

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

和用法

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

答案 18 :(得分: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;
    ...
}

答案 19 :(得分: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。

答案 20 :(得分:0)

declare @p1Flags    tinyint = 1|4|8|16, --> enum flags
        @p2Flags    tinyint = 1|4|16|32


print 'Person 1:'+ [Utilities].[ToBinaryString](@p1Flags) 
print 'Person 2:'+ [Utilities].[ToBinaryString](@p2Flags) 


declare @ix int =1,
        @Person1 varchar(8) =reverse([Utilities].[ToBinaryString](@p1Flags)),
        @Person2  varchar(8) =reverse([Utilities].[ToBinaryString](@p2Flags)),
        @match bit =0,
        @matched int=0;

        --> compare only the range that can hold data
declare @lenPerson1 tinyint = len(@Person1) - Charindex('1',reverse(@Person1),0)+1  
      , @lenPerson2 tinyint = len(@Person2) - Charindex('1',reverse(@Person2),0)+1  

while @ix <= @lenPerson1 
begin
     if @ix > @lenPerson2
        break;

     set @match= iif (SUBSTRING(@Person1,@ix,1)=SUBSTRING(@Person2,@ix,1) and SUBSTRING(@Person1,@ix,1)='1',1,0)

     if  @match=1 --> same interest 
        set @matched=@matched+1

    set @ix= @ix+1
end;


declare @result decimal(7,4) = (1.*@matched)*100./(1.* @lenPerson1)
print '-------------------------------------------------------------------------'
print 'Matching bits in bitmap: '+ cast(@matched as varchar(2))+' of '+cast(@lenPerson1 as varchar(2))+ ' = ' +cast(@result as char(8)) +'%'

答案 21 :(得分:-4)

在onViewHolder中将onClickListiner设置为任意视图,并在侧面单击时使用此代码:

Toast.makeText(Drawer_bar.this,&#34; position&#34; + position,Toast.LENGTH_SHORT).show();

Drawer_Bar替换为您的活动名称。