Отримайте клік по позиції та його позиції в RecyclerView


105

Я заміна мого ListViewз RecyclerView, списком показує нормально, але я хотів би знати , як отримати Clicked елемента і його позицію, аналогічну методу OnItemClickListener.onItemClick(AdapterView parent, View v, int position, long id)ми використовуємо в ListView.

Дякую за ідеї!


1
перевірити цей підручник wiki.workassis.com/android-recyclerview-example
Bikesh M


Найпростіший спосіб як для мене: CustomSelectionCallback
ATES

Відповіді:


177

За посиланням: Чому RecyclerView не має OnItemClickListener ()? і чим RecyclerView відрізняється від Listview? , а також загальну ідею @ Данкана, я даю тут своє рішення:

  • Визначте один інтерфейс 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);
  • В Adapterі ViewHolder:

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


22
використовувати метод getLayoutPosition (), оскільки getPosition () тепер вивільняється.
Анкур Чадхарі

2
спасибі за цей фрагмент коду :) лише одна порада: посилайтесь на статичне private static RecyclerViewClickListener itemListener;статичним способом у конструкторі.
Девід Артман

1
@khurramengr Я в кінцевому підсумку додав слухача до кожного елемента методу onBindViewHolder. Більше того, на моєму списку було не все, що можна натискати (лише частина цього пункту).
Ferran Negre

1
Якщо ви тут не використовуєте WeakReference new MyRecyclerViewAdapter(context, this):? Це може спричинити витік пам’яті
RamwiseMatt,

2
public void recyclerViewListClicked(View v, int position);Модифікатор publicє надлишковим для методів інтерфейсу
Джоель Раджу

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

4
Дякую. getAdapterPosition () - це те, що мені було потрібно.
Аяз Аліфов

1
Дякую за людину з кодом !! Врятував мені день. Я не був впевнений, куди поставити getAdapterPosition () і, слідуючи за вашим кодом, я працював ... Приємно і просто :)
Vinay Vissh

Дякую, чувак, дуже потрібен твій код! Щаслива людина
Naveen Nirban Yadav

13

Ось приклад встановлення слухача кліків.

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

    }

Що таке getAdapterPostion (); тут?
TheDevMan

1
натиснуто положення перегляду. не є спеціальним методом.
Гілберто Ібарра

Це виглядає як найчистіший спосіб зробити це, тим більше, що ви майже завжди зацікавлені в отриманні даних за допомогою позиції і, можливо, не маєте доступу до об'єкта RecyclerView.
FrostRocket

Велике спасибі заint position = getAdapterPosition();
Шилендра Мадда

Зверніть увагу, що виклик getAdapterPosition під час оновлення списку, наприклад, через дзвінок notififyXYZ, повернеться -1
Девід

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

    }
}

7

створити файл 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
  }
}));

RecyclerItemClickListenerне є класом Android за замовчуванням, вам слід надати бібліотеку, яку ви використовуєте, або сам клас.
Грег

@Greg спасибо !! я забув дописувати!
MazRoid

5

Якщо ви хочете натиснути подію recycle-View від діяльності / фрагмента замість адаптера, ви також можете скористатися наступним способом.

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

Ви також можете використовувати інші довгі способи, такі як використання інтерфейсу


,, привіт, але що робити, якщо нам також потрібно буде натиснути позицію товару. ?
mfaisalhyder

Ви можете просто встановити позицію елемента в TAG через адаптер, а потім отримати тег, як згадувалося вище txtStatusChange.getTag (). ToString ()
Amandeep Rohila

@AmandeepRohila Для того, щоб код працював, спочатку потрібно прокрутити до кінця горизонтальний перегляд рециркулятора. Тільки тоді тост спрацьовує. Чи не існує способу змусити це працювати, не спочатку прокручуючи вперед і назад?
iOSAndroidWindowsMobileAppsDev

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

Що це за чаклунство? Працює чудово.
Боллінг

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

    }
}
}

1

RecyclerView не забезпечує такий спосіб.

Для управління подіями натискання на RecyclerView я закінчив впроваджувати onClickListener у своєму адаптері під час прив’язки ViewHolder: У своєму ViewHolder я зберігаю посилання на кореневий вигляд (як це можна зробити із ImageViews, TextViews тощо) та при прив'язці the viewHolder Я встановлюю на ній тег із інформацією, що мені потрібна для обробки клацання (наприклад, положення) та користувача clickliste


3
так, ми можемо встановити прослуховувач кліків у ViewHolder, але мені потрібно повернути переглянуте зображення та позицію мого фрагмента для подальшого процесу
Xcihnegn

1

Ось найпростіший і найпростіший спосіб знайти позицію клацнутого елемента:

Я також зіткнувся з тією ж проблемою.

Я хотів знайти позицію клацнутого / вибраного елемента RecyclerView () і виконати деякі конкретні операції над цим елементом.

Метод getAdapterPosition () працює як шарм для подібних матеріалів. Я знайшов цей метод після дня тривалих досліджень і після спробу численних інших методів.

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

Не потрібно використовувати зайвий метод. Просто створіть глобальну змінну під назвою 'position' та ініціалізуйте її за допомогою getAdapterPosition () у будь-якому з основних методів адаптера (класу чи подібного).

Ось коротка документація за цим посиланням .

getAdapterPosition додано у версії 22.1.0 int getAdapterPosition () Повертає положення адаптера елемента, представленого цим ViewHolder. Зауважте, що це може відрізнятися від getLayoutPosition (), якщо є оновлення адаптера, що очікують на розгляд, але новий пропуск макета ще не відбувся. RecyclerView не обробляє будь-які оновлення адаптера до наступного переходу макета. Це може створити тимчасові невідповідності між тим, що бачить користувач на екрані, та вмістом адаптера. Ця невідповідність не є важливою, оскільки вона буде менше 16 мс, але це може бути проблемою, якщо ви хочете використовувати позицію ViewHolder для доступу до адаптера. Іноді вам може знадобитися отримати точне положення адаптера, щоб виконати деякі дії у відповідь на події користувача. У цьому випадку слід скористатися цим методом, який обчислює положення адаптера ViewHolder.

Раді допомогти. Сміливо задайте сумніви.


який найпростіший і найпростіший спосіб отримати значення клацнутого елемента RecyclerView?
अक्षय परूळेकर

1

Моє просте рішення

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, вона тримається у власнику (або, можливо, її слід називати слухачем)

Я сподіваюся, що це буде корисно

Моє перше повідомлення; P


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

        }
    });
}

3
Будь ласка, додайте пояснення, просто демпінговий код без введення та пояснення, як це вирішує проблему, не дуже корисно.
Марк Ротвевель

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 на основі контексту, заданого вами у діяльності чи фрагменті та методах накладення.


Гарне рішення вище. Чи можете ви додати до сказаного, щоб показати, як має виглядати метод onItemClick у "Активізмі"? Я намагаюся передати позицію предмета до наміру (щоб відкрити наступну діяльність), і я продовжую отримувати неправильну позицію.
AJW

0

Щоразу використовую інший підхід. Люди здаються, що вони зберігають або отримують позицію на перегляді, а не зберігають посилання на об'єкт, який відображається ViewHolder.

Я використовую цей підхід замість цього і просто зберігаю його у ViewHolder, коли onBindViewHolder () викликається, і встановлює посилання на null в onViewRecycled ().

Кожен раз, коли 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;
    ...
}

0

Коротке розширення методу Котліна
повертає абсолютне положення всіх елементів (а не положення лише видимих ​​елементів).

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

І використання

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

0

Використовуйте getLayoutPosition () у власному методі Java інтерфейс. Це поверне вибране положення предмета, перевірте повну інформацію

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


1
Ласкаво просимо до переповнення стека! Хоча посилання - це чудовий спосіб обміну знаннями, вони насправді не дадуть відповіді на питання, якщо вони в майбутньому будуть порушені. Додайте до своєї відповіді необхідний зміст посилання, яке відповідає на запитання. Якщо зміст занадто складний або занадто великий, щоб тут вмістити, опишіть загальну ідею запропонованого рішення. Не забудьте завжди зберігати посилання на веб-сайт оригінального рішення. Дивіться: Як написати гарну відповідь?
sɐunıɔ ןɐ qɐp

0

Від дизайнера ви можете встановити onClickвластивість listItem методом, визначеним одним параметром. У мене є приклад, визначений нижче. Метод getAdapterPosition дасть вам індекс вибраного спискуItem.

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

Щоб отримати інформацію про налаштування RecyclerView, перегляньте документацію тут: https://developer.android.com/guide/topics/ui/layout/recyclerview


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

3
Відповідаючи на старе запитання, ваша відповідь була б набагато кориснішою для інших користувачів StackOverflow, якщо ви включили якийсь контекст, щоб пояснити, як допомагає ваша відповідь, особливо на питання, на яке вже є прийнята відповідь. Див.: Як написати гарну відповідь .
Девід Бак

0

Після безлічі спроб і помилок я виявив, що існує дуже простий спосіб зробити це, створивши інтерфейс в класі адаптерів і реалізуючи, що в фрагменті зараз тут відбувається поворот, я встановив модель перегляду всередині своєї функції переосмислення, присутньої в фрагмент, тепер ви можете надсилати дані з цієї функції у відемодель і звідти куди завгодно.

Я не знаю, чи цей метод є гарним методом кодування, але, будь ласка, повідомте мене про це в коментарях, і якщо хтось хоче побачити, дайте мені знати в розділі коментарів.


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

            })

Якщо використовувати Котлін


Хоча цей код може вирішити питання, включаючи пояснення, як і чому це вирішує проблему, справді допоможе покращити якість вашої публікації та, ймовірно, призведе до збільшення кількості голосів. Пам'ятайте, що ви відповідаєте на запитання читачів у майбутньому, а не лише про людину, яка зараз задає питання. Будь ласка, відредагуйте свою відповідь, щоб додати пояснення та вказати, які обмеження та припущення застосовуються.
Богдан Опір

-4

У onViewHolder встановіть onClickListiner на будь-який вид і в бічній кнопці використовуйте цей код:

Toast.makeText (Drawer_bar.this, "позиція" + положення, Toast.LENGTH_SHORT) .show ();

Замініть Drawer_Barсвоє ім’я діяльності

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.