簡體   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