Получить выбранный элемент и его позицию в RecyclerView


105

Я заменяю свой ListViewна RecyclerView, список показывает нормально, но я хотел бы знать, как получить выбранный элемент и его положение, аналогично методу, который 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? , а также общую идею @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);
  • В 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. Более того, не весь мой элемент списка был доступен для кликов (только часть элемента).
Ферран Негре

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 (), и, следуя вашему коду, он заработал ...
Красиво

Большое спасибо, чувак, твой код был именно таким, как мне нужно! Счастливый человек
Навин Нирбан Ядав

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();
Шилендра Мадда 08

Обратите внимание, что вызов 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) {

    }
}

8

создать файл 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 thanx !! я забыл опубликовать!
MazRoid

5

Если вам нужно событие Click для 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 ()
Амандип Рохила

@AmandeepRohila Для того, чтобы код работал, мне сначала нужно прокрутить до конца горизонтального recyclerview. Только тогда тост работает. Разве нет способа заставить его работать без предварительной прокрутки вперед и назад?
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) {
            }
        }
    )
);

Что это за колдовство? Прекрасно работает.
Bolling

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 и т. Д.) И при привязке viewHolder Я установил на нем тег с информацией, которая мне нужна для обработки щелчка (например, положение) и прослушивателя щелчков


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

В адаптере onClickLictener в элементе
onBindViewHolder

holder.holderButton.setOnClickListener(v -> {
            positionHolder.setPosition(position);
            notifyDataSetChanged();
        });

Теперь всякий раз, когда вы меняете позицию в RecyclerView, она удерживается в держателе (или, возможно, его следует называть Listener)

Надеюсь, это будет полезно

Мой первый пост; 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 в Activity? Я пытаюсь передать позицию элемента в намерение (чтобы открыть следующее действие), но получаю неправильную позицию.
AJW 03

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

Короткое расширение для метода Kotlin
возвращает абсолютное положение всех элементов (а не положение только видимых элементов).

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
Добро пожаловать в Stack Overflow! Хотя ссылки являются отличным способом обмена знаниями, они не ответят на вопрос, если в будущем они сломаются. Добавьте к своему ответу основное содержание ссылки, которая отвечает на вопрос. Если содержание слишком сложное или слишком большое, чтобы здесь поместиться, опишите общую идею предлагаемого решения. Не забывайте всегда сохранять ссылку на веб-сайт исходного решения. См .: Как мне написать хороший ответ?
sɐunıɔ ןɐ qɐp

0

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

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

После большого количества проб и ошибок я обнаружил, что есть очень простой способ сделать это - создать интерфейс в классе адаптера и реализовать его во фрагменте. Теперь здесь происходит поворот, я создал экземпляр модели представления внутри моей функции переопределения, присутствующей в fragment, теперь вы можете отправлять данные из этой функции в viemodel и оттуда куда угодно.

Я не знаю, является ли этот метод хорошим методом кодирования, но, пожалуйста, дайте мне знать в комментарии, и если кто-то хочет увидеть, дайте мне знать в разделе комментариев, я регулярно открываю поток стека.


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.