- RecyclerView Item Click Listener the Right Way
- Example Scenario
- Project Creation
- Data model
- Recyclerview Adapter and view holder
- Item Click the bad way
- Let us fix it
- Defining item click listener for RecyclerView in Android
- grantland / post.md
- This comment has been minimized.
- matthewmichihara commented Jul 3, 2014
- This comment has been minimized.
- alexnavratil commented Jul 3, 2014
- This comment has been minimized.
- jacobtabak commented Oct 4, 2014
- This comment has been minimized.
- AmauryEsparza commented Feb 16, 2015
- This comment has been minimized.
- lnikkila commented Mar 9, 2015
- This comment has been minimized.
- ghost commented Apr 29, 2015
- This comment has been minimized.
- ghost commented Jul 9, 2015
- This comment has been minimized.
- riyazMuhammad commented Jul 22, 2015
- This comment has been minimized.
- yosraa commented Jul 30, 2015
- This comment has been minimized.
- dinigo commented Aug 20, 2015
- This comment has been minimized.
- IgorGanapolsky commented Oct 2, 2015
- This comment has been minimized.
- dinesh-gadri commented Nov 19, 2015
- This comment has been minimized.
- dinesh-gadri commented Nov 19, 2015
- This comment has been minimized.
- mayooresan commented Jan 6, 2016
- This comment has been minimized.
- dima925 commented Mar 14, 2016
- This comment has been minimized.
- shubham08gupta commented May 1, 2016
- This comment has been minimized.
- MansoorJafari commented Jun 29, 2016
- This comment has been minimized.
- pradeepkumarreddyk commented Jul 12, 2016
- This comment has been minimized.
- EliudNjuguna commented Sep 17, 2016
- This comment has been minimized.
- devmike01 commented Oct 17, 2016
- This comment has been minimized.
- MinaGabriel commented Nov 18, 2016
- This comment has been minimized.
- SkymanOne commented Dec 6, 2016 •
- This comment has been minimized.
- JSila commented Feb 15, 2017
- This comment has been minimized.
- ayetolusamuel commented Apr 11, 2018
- This comment has been minimized.
- ax-vasquez commented Jul 20, 2018
- This comment has been minimized.
- deweysia commented Nov 11, 2018
- This comment has been minimized.
- nayzawoo commented Feb 11, 2019
- This comment has been minimized.
- imrankhanissm commented Feb 19, 2019
- This comment has been minimized.
- parthdesai1208 commented May 27, 2019
- This comment has been minimized.
- JaiMistry commented Feb 11, 2020
- This comment has been minimized.
- IrshadKasana commented Sep 8, 2020
- О RecyclerView и выделении элементов
- Содержание
- 1. Немного о ViewHolder’ах
- 2. Вкратце о RecyclerView
- 3. Выделяем элементы
- 4. Заключение + Бонус
RecyclerView Item Click Listener the Right Way
Some Android developers wonder why Google created a view like Recyclerview without a click listener(given the fact that the deprecated ListView has an item click listener).
Because there is no standard way of setting a click listener, new developers tend to confuse on the right way of doing it. In this article, I will show you how to do it in a proper way using an example scenario.
Example Scenario
- There is a Recyclerview adapter with a Recyclerview with a list of items(Users in this case).
- What we want is that when an item is clicked, we get the item’s model(User) information and may be pass it to a second activity.
Project Creation
From Android Studio, create an empty android project(Select the Kotlin support option) and name your activity, MainActivity.
- Delete the default ‘Hello World’ TextView in activity_main.xml .
- Add recyclerview and cardview dependencies in app level build.gradle file as shown below.
Add recyclerview in activity_main.xml where you removed the textview as shown below.
Ok we are good to go. The assumption is that you have worked with the recyclerview(in Java) before and know how to create a recyclerview adapter.. Next, we create the model class containing username and phone.
Data model
Sweet Kotlin. Just the above line of code gives us access to a setter and getter under the hood and other methods like toString. Check more at https://kotlinlang.org/docs/reference/data-classes.html .
Next, we create our view holder and adapter. Pay attention here because it is the most important part of what this article addresses.
Recyclerview Adapter and view holder
- Create a new Kotlin file called RecyclerAdapter.kt
- Next we create our item_user.xml layout as follows
The item_user has two textviews which holds the name and phone.
Next we create our view holder. As usual, our view holder has a constructor with an itemView as parameter and we get a reference to our views from item_user layout .
Then we create our adapter with the list of users as a parameter. An adapter contains the list of users
Item Click the bad way
Note that in onBindView, we can have access to the the current clicked item and thus open a new activity from here and pass our data..
This will work perfectly but it is a bad practice because
- It is not a good practice opening an Activity from a viewholder context
- Note that onBindViewHolder is called as your views are populated during scrolling. Thus you will have numerous calls to setOnClickListener.
Let us fix it
The way that you should do is that you create an ItemClickListener interface with one method ontemClicked with parameter User.
- We then pass modify the Adapter’s constructor to take the users list and an OnItemClickListener interface
- We also modify the the ViewHolder to have a bind function which takes a user and itemClick interface as follows.
This is all we have to do. We just have to implement the interface in our MainActivity .
Источник
Defining item click listener for RecyclerView in Android
Android RecyclerView doesn’t come with the Item Click Listener that you have with ListView. You will have to implement the item clicke listener yourself. Here is an example of how to implement the view holder item clicker listener in RecyclerView. In a nutshell, The Activity class will implement an interface for onClick event, this interface will be passed to the RecyclerView Adapter class, then the ViewHolder class in the RecyclerView will call onClick method defined in the interface, which will pass the view and position of the clicked item to the onClick implementation in the Activity class.
1. We will need a listener interface.
2. In your ViewHolder class in your RecyclerView adapter, implement View.OnClickListener, bind the listener to the view. In the onClick method, call the onClick method of the interface OnItemClickListener. This should be passed in from your RecycyclerView’s constructor. The actual implementation of the onclick event will be from an activity or fragment that contains this RecyclerView. The important line here is clickListener.onClick(view, getPosition()); where clickListener is a global variable in your RecyclerView class, again it should’ve passed in from your RecyclerView’s constructor.
3. The onClick implementation in the Activity class, the important line here is mAdapter.setClickListener(this); and the onClick method. The onClick method gets triggered from the ViewHolder’s onClick method in your RecyclerView class, which passes the view and position of the clicked item.
4. All together:
The interface class, ItemClickListener.java
The RecyclerView Adapter class, CityAdapter.java
The Activity class, CityActivity.java
The layout files are not provided for above sample are not provided since this post is not about layout.
Источник
grantland / post.md
RecyclerView item onClick
RecyclerView does not have an OnItemClickListener like it’s predecessor, ListView . However, detecting item clicks is pretty simple.
Set an OnClickListener in your ViewHolder creation:
Add touch feedback to your item layout:
This comment has been minimized.
Copy link Quote reply
matthewmichihara commented Jul 3, 2014
how do you find out about all these ?android:attr values? I never know what exists
This comment has been minimized.
Copy link Quote reply
alexnavratil commented Jul 3, 2014
This comment has been minimized.
Copy link Quote reply
jacobtabak commented Oct 4, 2014
You should not couple your ViewHolders and ItemClickListeners. Please see a better solution here.
This comment has been minimized.
Copy link Quote reply
AmauryEsparza commented Feb 16, 2015
@jacobtabak that exactly is what i think, but how you get the position element was clicked on the RecyclerView? I’m just find answers like above.
This comment has been minimized.
Copy link Quote reply
lnikkila commented Mar 9, 2015
This comment has been minimized.
Copy link Quote reply
ghost commented Apr 29, 2015
@jacobtabak how to get click listener on individual views in the row item. The click is intercepted by on touch right??
This comment has been minimized.
Copy link Quote reply
ghost commented Jul 9, 2015
This comment has been minimized.
Copy link Quote reply
riyazMuhammad commented Jul 22, 2015
This comment has been minimized.
Copy link Quote reply
yosraa commented Jul 30, 2015
how to get startactivity in onclick()
This comment has been minimized.
Copy link Quote reply
dinigo commented Aug 20, 2015
This works on my head, but doesn’t run as expected. The onClick() is never triggered, and I can’t find why
This comment has been minimized.
Copy link Quote reply
IgorGanapolsky commented Oct 2, 2015
@jacobtabak Read the comment in the solution you linked to:
This will not provide any clue about which button or view (within the item) was clicked.
This comment has been minimized.
Copy link Quote reply
dinesh-gadri commented Nov 19, 2015
how to delete row in recycler view.
plzz help me
This comment has been minimized.
Copy link Quote reply
dinesh-gadri commented Nov 19, 2015
how to delete row in recycle view when click on delete than that row is delete..plzzz help me
This comment has been minimized.
Copy link Quote reply
mayooresan commented Jan 6, 2016
@demil133 after adding android:clickable=»true» to the parent element for the item’s layout in xml, it started to work. Hope it’ll help someone out there.
This comment has been minimized.
Copy link Quote reply
dima925 commented Mar 14, 2016
Good sample. it’s well for my app.
This comment has been minimized.
Copy link Quote reply
shubham08gupta commented May 1, 2016
This comment has been minimized.
Copy link Quote reply
MansoorJafari commented Jun 29, 2016
Hi
I have a recycler view with event onTap Listener and in item row I have a TextView that have click listener event
in my code OnTap only work. mean after click textview event onTap run and textview event dont work.
please help for solve this problem.
This comment has been minimized.
Copy link Quote reply
pradeepkumarreddyk commented Jul 12, 2016
where did you add touch feedback to item layout
This comment has been minimized.
Copy link Quote reply
EliudNjuguna commented Sep 17, 2016
How do you implement onClickListener on GridLayout using the RecyclerView
This comment has been minimized.
Copy link Quote reply
devmike01 commented Oct 17, 2016
This code doesn’t work, but this does work
This comment has been minimized.
Copy link Quote reply
MinaGabriel commented Nov 18, 2016
the base class doesn’t have any on click method.
This comment has been minimized.
Copy link Quote reply
SkymanOne commented Dec 6, 2016 •
but can use int item instead of String item and it’s easier work with items
This comment has been minimized.
Copy link Quote reply
JSila commented Feb 15, 2017
getPosition is deprecated, use getAdapterPosition instead.
This comment has been minimized.
Copy link Quote reply
ayetolusamuel commented Apr 11, 2018
thanks, this save me from item clicklistener mess.
Though this is what i use.
int itemPosition = getLayoutPosition();
Products products = productsArrayList.get(itemPosition);
Thanks for the clue
This comment has been minimized.
Copy link Quote reply
ax-vasquez commented Jul 20, 2018
Thanks! This is by far the cleanest solution I have seen for this. Helped a lot!
This comment has been minimized.
Copy link Quote reply
deweysia commented Nov 11, 2018
Short and concise. Thanks!
This comment has been minimized.
Copy link Quote reply
nayzawoo commented Feb 11, 2019
I use this method
This comment has been minimized.
Copy link Quote reply
imrankhanissm commented Feb 19, 2019
This comment has been minimized.
Copy link Quote reply
parthdesai1208 commented May 27, 2019
thanks for the code, you saved my lot of time.
This comment has been minimized.
Copy link Quote reply
JaiMistry commented Feb 11, 2020
how to get startactivity in onclick()
This comment has been minimized.
Copy link Quote reply
IrshadKasana commented Sep 8, 2020
how to implement onItemClickListener on individual items/icons of viewHolder in a recyclerView and perform actions on them inside fragment/activity, but not inside the adapter
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Источник
О RecyclerView и выделении элементов
Содержание
1. Немного о ViewHolder’ах
До выхода в свет Android SDK 5.0 Lollipop для отображения списков и таблиц использовались виджеты ListView и GridView. Общей рекомендацией при работе с этим виджетом было использование паттерна ViewHolder. Суть паттерна заключается в том, что для каждого элемента списка создаётся объект, хранящий ссылки на отдельные вьюхи внутри элемента. Таким образом, приходится выполнять достаточно дорогой вызов findViewById(int) только один раз при создании элемента.
Пример типичного ViewHolder’а прямиком из руководств гугла:
Cсылка на такой холдер для каждого элемента сохраняется в корневом layout’е, используя метод setTag(int, Object) (с моей точки зрения тот ещё костыль).
2. Вкратце о RecyclerView
К выходу Android SDK 5.0 Lollipop разработчиков Google наконец-то озарило, что два вышеперечисленных виджета морально устарели и нужно бы заменить их на нечто более стильное, модное и молодёжное. Было принято решение не переделывать старые виджеты, а написать новый. Так и появился на свет RecyclerView. Так в чём же его отличия, спросите вы?
Я приведу вкратце основные, а для более полного их раскрытия советую к ознакомлению вот эту статью на хабре. Итак:
- Сам виджет больше не берёт на себя обязанность по размещению элементов. Для этого появились LayoutManager’ы.
- Паттерн ViewHolder стал обязательным. Причём виджет научился заново использовать уже созданные ViewHolder’ы и удалять уже не используемые (отсюда и название), что благоприятно сказывается на быстродействии и размере используемой памяти.
- Новый, удобный способ работы с анимацией.
Я попробовал его и виджет оставил у меня противоречивые впечатления. С одной стороны, да, здорово, что теперь использование ViewHolder’а является обязательным, работает вроде тоже быстрей, памяти жрёт меньше. С другой стороны, есть проблемы со сложностью и недоделанностью виджета.
Что я понимаю под сложностью? Если что-то не работало в ListView (или работало не так как задумано) всегда можно было залезть в исходники, разобраться, в чём ошибка, исправить её, подоткнуть костылей тут и там и всё начинало работать. RecyclerView гораздо сложнее в плане логики работы, мозг сломаешь, пока разберёшься. Я пытался, но забросил, уж слишком много времени и сил для этого нужно.
Вторая проблема — банальное отсутствие функционала, присутствовавшего в ListView и GridView. За примерами далеко ходить не надо — стандартный функционал выделения элементов (дальнейшая тема этой статьи), отступы между элементами. Раньше, чтобы добавить всё это, нужно было написать буквально пару строчек кода, теперь на это уйдут уже десятки строк. Есть анимации, но только для добавления/удаления/редактирования элемента. Если же вы хотите, например, анимировать частичное изменение элемента, то к вам в дверь уже стучится птица обломинго. Виджет не поддерживает анимацию части элемента, и если анимировать элемент извне (из адаптера, например), то лучше этого не делать — подобные манипуляции оставляют элементы виджета (те самые ViewHolder’ы) в неопределённом состоянии, что приводит к совершенно фантастическому поведению вашего списка.
Резюмируя — если у вас в проекте используются старые виджеты и вы не используете анимации, то лучше пока оставить всё как есть и дождаться, когда виджет наполнят отсутствующим функционалом. Если же вы хотите простые анимации и при этом взаимодействие пользователя с виджетом подразумевается простое — попробуйте RecyclerView, вдруг понравиться.
3. Выделяем элементы
Итак, перейдём к главному — к технической части статьи. Поговорим о том, как выделять элементы в RecyclerView. Сразу оговорюсь — идея реализации почерпнута из замечательной серии статей Билла Филлипса про RecyclerView (ссылки в конце), так что всё нижеследующее можно считать вольным кратким пересказом.
В ListView для выделения элементов использовался метод setChoiceMode(int), RecyclerView же понятия не имеет, что элементы могут выделяться, поэтому мы должны научить этому наш адаптер.
Схема такая:
На диаграмме я схематично обозначил связи между объектами. Пунктирные стрелки — ссылки, остальные — вызовы методов. Зелёным я обозначил объекты, которые непосредственно реализуют логику выделения.
Принцип работы получается следующий:
- ViewHolderWrapper устанавливает себя в качестве ClickListener’а для корневой вьюхи ViewHolder’а и начинает получать события onClick и onLongClick. В зависимости от реализации он может просто проксировать эти события в HolderClickObservable (ViewHolderClickWrapper), либо, исходя из текущего статуса SelectionHelper’а выделять элемент вызовом setItemSelected(ViewHolder, boolean) (ViewHolderMultiSelectionWrapper).
- SelectionHelper сохраняет информацию о выделенных элементах и оповещает слушателей (SelectionObserver) об изменении выделения.
- Слушатель (в нашем случае адаптер) отвечает за визуальное отображение выделения элемента, а также взаимодействия с ним (на диаграмме вызов startActionMode у Activity).
В самом адаптере необходимо сделать следующие изменения:
1. Создать SelectionHelper и зарегистрировать слушателей (в данном случае сам адаптер, но это может быть и Activity, например)
2. Обернуть создаваемые ViewHolder’ы во ViewHolderWrapper нужного типа.Метод wrapSelectable(ViewHolder) у SelectionHelper’а:
3. Не забывать прицеплять наши ViewHolder’ы к SelectionHelper’у в методе onBindViewHolder(ViewHolder, int) нашего адаптера!
Это нужно по причине того, что пока нет другого способа получить от RecyclerView список используемых в настоящий момент ViewHolder’ов. Если не вести их учёт, при необходимости обновить отрисовку выделения у всех выбранных элементов (пользователь закрыл ActionMode, например), SelectionHelper просто не сможет этого сделать. Вьюхи останутся выглядеть выделенными, когда по факту таковыми не будут.
Вы спросите — «А почему бы просто не запоминать выделяемые ViewHolder’ы в методе setItemSelected(ViewHolder, boolean)?». Тут как раз сказывается особенность RecyclerView — он использует заново уже созданные ViewHolder’ы.
Выглядит это примерно так:
- Открываем приложение. На экране 10 элементов — 10 ViewHolder’ов создано для них.
- Запускаем ActionMode, начинаем выделять элементы — 1,2,3.
- Прокручиваем вьюху вниз, видим элементы с 10 по 20. Думаете, что теперь в памяти висит 20 ViewHolder’ов? Как бы ни так! Для части данных RecyclerView создаст новые ViewHolder’ы, а для другой заново использует уже имеющиеся. Причём неизвестно в каком порядке.
- Теперь если мы прокрутим вьюху обратно вверх, часть из наших 10 ViewHolder’ов будет уничтожена, вместо них будут созданы новые. Оставшаяся часть будет использована заново и совершенно не обязательно для тех же позиций.
- Отменяем ActionMode. SelectionHelper должен раскидать слушателям уведомления о сменившемся выделении на элементах с указанием ViewHolder’а для каждого элемента, но он уже не владеет актуальными данными, все Holder’ы поменялись!
В результате это приведёт к тому, что часть элементов останется отображаться с выделением.
И здесь становится очевидным ещё один важный момент — нельзя сохранять строгие ссылки (strong reference) на ViewHolder’ы! Они могут быть удалены из RecyclerView в зависимости от фазы Луны и желания левой пятки Ларри Пейджа. В этом случае, если мы будем хранить строгие ссылки на них, случится утечка памяти. Поэтому для хранения ссылок в ViewHolderWrapper и WeakHolderTracker используются только WeakReference.
4. Также важно не забыть в onBindViewHolder(ViewHolder, int) визуально отобразить выделение если оно есть (если нет — не забыть убрать!). Вы же помните, что для не выделенного элемента может быть использован ViewHolder, ранее использовавшийся для не выделенного и наоборот?
У меня это реализовано следующим образом:
4.1. SelectableRecyclerViewAdapter.onBindViewHolder(ViewHolder, int)
4.2. layout-файл для элемента
CheckableAutofitHeightFrameLayout добавляет к FrameLayout всего 2 вещи: во-первых, он всегда квадратный (смотри onMeasure(int, int)) и, во-вторых, добавляет к DrawableStates (те самые, которые используются в xml) состояние state_checked. В результате, для отображения выделения у такого layout’а можно использовать StateListDrawable на вроде этого:и все детали отображения уползают в xml-ки, в Java только нужно установить соответствующие состояния.
5. Передать событие onSelectableChanged(boolean) в Activity и запустить ActionMode:
Как вы видите, при запуске ActionMode, она регистрирует себя как SelectionObserver. Таким образом, можно обновлять количество выделенных элементов в заголовке. Не забудьте вызвать unregisterSelectionObserver(SelectionObserver) при закрытии!
4. Заключение + Бонус
Кажется, с выделением разобрались. Весь исходный код также можно посмотреть на GitHub.
В заключение вкратце приведу ещё несколько фишек для работы с RecyclerView, которые вы можете найти в примере.
1. Если не нужно выделять элементы, а нужно просто обрабатывать нажатия, вместо ViewHolderMultiSelectionWrapper оборачивайте элементы в ViewHolderClickWrapper методом wrapClickable(ViewHolder). Сам адаптер в таком случае будет выглядеть примерно так:
Виджет подбирает ширину столбцов в зависимости от параметра columnWidth. Важный момент: если доступная ширина 330 пикселей, а мы передадим желаемую ширину 100, в итоге в таблице будет 3 столбца по 110 пикселей и элементы будут этой ширины. Именно поэтому я также сделал CheckableAutofitHeightFrameLayout автоматически изменяющим свою высоту в зависимости от ширины.
3. Для добавления отступов между элементами можно выставить paddingTop/Left у RecyclerView и marginRight/Bottom у элементов, однако это выглядит как костыль. Рекомендуемым способом является добавление ItemDecoration к RecyclerView. В примере можно найти несколько. Для добавления отступов к обычному GridLayoutManager (под «обычным» я имею ввиду GridLayoutManager со стандартным SpanSizeLookup, в нём каждый элемент занимает 1 span) можно использовать
Источник