Почему у RecyclerView нет onItemClickListener()?
Я изучал RecyclerView
, и я был удивлен, увидев, что RecyclerView
не имеет onItemClickListener()
. Поскольку RecyclerView
extends
android.view.ViewGroup
и ListView
продолжается
android.widget.AbsListView
. Однако я решил проблему, написав onClick
в своем RecyclerView.Adapter
:
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
@Override
public void onClick(View v) {
}
}
Но все же я хочу знать, почему Google удалил onItemClickListener()
?
Есть ли проблема с производительностью или что-то еще?
Ответы
Ответ 1
tl; dr 2016 Используйте RxJava и PublishSubject, чтобы выставить наблюдаемый для кликов.
public class ReactiveAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
String[] mDataset = { "Data", "In", "Adapter" };
private final PublishSubject<String> onClickSubject = PublishSubject.create();
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
final String element = mDataset[position];
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onClickSubject.onNext(element);
}
});
}
public Observable<String> getPositionClicks(){
return onClickSubject.asObservable();
}
}
Оригинальное сообщение:
Поскольку введение ListView
, onItemClickListener
было проблематичным. В тот момент, когда у вас есть прослушиватель кликов для любого из внутренних элементов, обратный вызов не запускается, но он не был уведомлен или хорошо документирован (если вообще), поэтому было много путаницы и SO-вопросов об этом.
Учитывая, что RecyclerView
делает это еще дальше и не имеет понятия строки/столбца, а представляет собой произвольно установленное количество детей, они делегировали onClick каждому из них или программисту реализация.
Вспомните RecyclerView
не как замену ListView
1:1, а скорее как более гибкий компонент для сложных случаев использования. И, как вы говорите, ваше решение - это то, что Google ожидает от вас. Теперь у вас есть адаптер, который может делегировать onClick интерфейсу, переданному конструктору, который является правильным шаблоном для ListView
и RecyclerView
.
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public IMyViewHolderClicks mListener;
public ViewHolder(View itemLayoutView, IMyViewHolderClicks listener) {
super(itemLayoutView);
mListener = listener;
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
imgViewIcon.setOnClickListener(this);
itemLayoutView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v instanceof ImageView){
mListener.onTomato((ImageView)v);
} else {
mListener.onPotato(v);
}
}
public static interface IMyViewHolderClicks {
public void onPotato(View caller);
public void onTomato(ImageView callerImage);
}
}
а затем на вашем адаптере
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
String[] mDataset = { "Data" };
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.my_layout, parent, false);
MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() {
public void onPotato(View caller) { Log.d("VEGETABLES", "Poh-tah-tos"); };
public void onTomato(ImageView callerImage) { Log.d("VEGETABLES", "To-m8-tohs"); }
});
return vh;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
// Get element from your dataset at this position
// Replace the contents of the view with that element
// Clear the ones that won't be used
holder.txtViewTitle.setText(mDataset[position]);
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return mDataset.length;
}
...
Теперь рассмотрим последний фрагмент кода: onCreateViewHolder(ViewGroup parent, int viewType)
подпись уже предлагает разные типы просмотров. Для каждого из них вам понадобится другой зритель, и впоследствии каждый из них может иметь другой набор кликов. Или вы можете просто создать общий зритель, который принимает любой вид и один onClickListener
и соответственно применяет. Или делегируйте один уровень оркестру, чтобы несколько фрагментов/действий имели один и тот же список с разными типами кликов. Опять же, вся гибкость на вашей стороне.
Это действительно необходимый компонент и довольно близок к тому, что было до сих пор реализовано нашими внутренними реализациями и улучшениями ListView
. Хорошо, что Google, наконец, признает это.
Ответ 2
Альтернативным решением является вариант предложенный Hugo Visser, Android GDE. Он предоставил вам класс без лицензии, чтобы просто вставить код и использовать его.
Использование:
ItemClickSupport.addTo(mRecyclerView)
.setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// do it
}
});
(он также поддерживает длительный щелчок по элементу)
Реализация (добавленные мной комментарии):
public class ItemClickSupport {
private final RecyclerView mRecyclerView;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnItemClickListener != null) {
// ask the RecyclerView for the viewHolder of this view.
// then use it to get the position for the adapter
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
mOnItemClickListener.onItemClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
}
};
private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mOnItemLongClickListener != null) {
RecyclerView.ViewHolder holder = mRecyclerView.getChildViewHolder(v);
return mOnItemLongClickListener.onItemLongClicked(mRecyclerView, holder.getAdapterPosition(), v);
}
return false;
}
};
private RecyclerView.OnChildAttachStateChangeListener mAttachListener
= new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View view) {
// every time a new child view is attached add click listeners to it
if (mOnItemClickListener != null) {
view.setOnClickListener(mOnClickListener);
}
if (mOnItemLongClickListener != null) {
view.setOnLongClickListener(mOnLongClickListener);
}
}
@Override
public void onChildViewDetachedFromWindow(View view) {
}
};
private ItemClickSupport(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
// the ID must be declared in XML, used to avoid
// replacing the ItemClickSupport without removing
// the old one from the RecyclerView
mRecyclerView.setTag(R.id.item_click_support, this);
mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}
public static ItemClickSupport addTo(RecyclerView view) {
// if there already an ItemClickSupport attached
// to this RecyclerView do not replace it, use it
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support == null) {
support = new ItemClickSupport(view);
}
return support;
}
public static ItemClickSupport removeFrom(RecyclerView view) {
ItemClickSupport support = (ItemClickSupport) view.getTag(R.id.item_click_support);
if (support != null) {
support.detach(view);
}
return support;
}
public ItemClickSupport setOnItemClickListener(OnItemClickListener listener) {
mOnItemClickListener = listener;
return this;
}
public ItemClickSupport setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
return this;
}
private void detach(RecyclerView view) {
view.removeOnChildAttachStateChangeListener(mAttachListener);
view.setTag(R.id.item_click_support, null);
}
public interface OnItemClickListener {
void onItemClicked(RecyclerView recyclerView, int position, View v);
}
public interface OnItemLongClickListener {
boolean onItemLongClicked(RecyclerView recyclerView, int position, View v);
}
}
также создайте файл values/ids.xml
и поместите его в него:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="item_click_support" type="id" />
</resources>
Этот класс работает, присоединяя RecyclerView.OnChildAttachStateChangeListener
к RecyclerView
. Этот слушатель уведомляется каждый раз, когда ребенок прикреплен или отсоединен от RecyclerView
. Этот код используется для добавления к просмотру прослушивателя нажатий/длинных кликов. Этот слушатель спросит RecyclerView
для RecyclerView.ViewHolder
, который содержит позицию.
Вы также можете адаптировать код, чтобы вернуть вам сам держатель, если вам нужно больше.
Имейте в виду, что он ПОЛНОСТЬЮ прекрасно обрабатывает его в вашем адаптере, устанавливая на каждом представлении вашего списка прослушиватель кликов, как и другой предложенный ответ. Это просто не самая эффективная вещь (вы создаете нового слушателя при каждом повторном использовании представления), но он работает, и в большинстве случаев это не проблема.
О том, почему RecyclerView
не имеет onItemClickListener
.
RecyclerView
- это набор инструментов, в отличие от старого ListView
он имеет меньше возможностей для сборки и большей гибкости. onItemClickListener
не является единственной функцией, удаляемой из ListView. Но у него много слушателей и метод, чтобы расширить его по своему вкусу, он гораздо более силен в правильных руках;).
По моему мнению, самая сложная функция, удаленная в RecyclerView
, - это быстрый прокрутка. Большинство других функций могут быть легко реализованы.
Ответ 3
Мне нравится этот путь, и я использую его
Внутри
public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
Положите
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_image_and_text, parent, false);
v.setOnClickListener(new MyOnClickListener());
И создайте этот класс в любом месте, где хотите.
class MyOnClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
int itemPosition = recyclerView.indexOfChild(v);
Log.e("Clicked and Position is ",String.valueOf(itemPosition));
}
}
Я читал перед этим, что есть лучший способ, но мне нравится, что это легко и не сложно.
Ответ 4
Android Recyclerview С onItemClickListener
, почему мы не можем попробовать, это работает как ListView
.
Источник: ссылка
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) {
}
}
И установите это для RecyclerView:
recyclerView = (RecyclerView)rootView. findViewById(R.id.recyclerView);
RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(getActivity(), new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
// TODO Handle item click
Log.e("@@@@@",""+position);
}
})
);
Ответ 5
Благодаря @marmor, я обновил свой ответ.
Я думаю, что это хорошее решение для обработки onClick() в конструкторе класса ViewHolder и передать его родительскому классу через интерфейс OnItemClickListener.
MyAdapter.java
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{
private LayoutInflater layoutInflater;
private List<MyObject> items;
private AdapterView.OnItemClickListener onItemClickListener;
public MyAdapter(Context context, AdapterView.OnItemClickListener onItemClickListener, List<MyObject> items) {
layoutInflater = LayoutInflater.from(context);
this.items = items;
this.onItemClickListener = onItemClickListener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = layoutInflater.inflate(R.layout.my_row_layout, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
MyObject item = items.get(position);
}
public MyObject getItem(int position) {
return items.get(position);
}
class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private TextView title;
private ImageView avatar;
public ViewHolder(View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
avatar = itemView.findViewById(R.id.avatar);
title.setOnClickListener(this);
avatar.setOnClickListener(this);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
//passing the clicked position to the parent class
onItemClickListener.onItemClick(null, view, getAdapterPosition(), view.getId());
}
}
}
Использование адаптера в других классах:
MyFragment.java
public class MyFragment extends Fragment implements AdapterView.OnItemClickListener {
private RecyclerView recycleview;
private MyAdapter adapter;
.
.
.
private void init(Context context) {
//passing this fragment as OnItemClickListener to the adapter
adapter = new MyAdapter(context, this, items);
recycleview.setAdapter(adapter);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//you can get the clicked item from the adapter using its position
MyObject item = adapter.getItem(position);
//you can also find out which view was clicked
switch (view.getId()) {
case R.id.title:
//title view was clicked
break;
case R.id.avatar:
//avatar view was clicked
break;
default:
//the whole row was clicked
}
}
}
Ответ 6
Ребята используют этот код в своем основном действии. Очень эффективный метод
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.users_list);
UsersAdapter adapter = new UsersAdapter(users, this);
recyclerView.setAdapter(adapter);
adapter.setOnCardClickListner(this);
Вот ваш класс адаптера.
public class UsersAdapter extends RecyclerView.Adapter<UsersAdapter.UserViewHolder> {
private ArrayList<User> mDataSet;
OnCardClickListner onCardClickListner;
public UsersAdapter(ArrayList<User> mDataSet) {
this.mDataSet = mDataSet;
}
@Override
public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_row_layout, parent, false);
UserViewHolder userViewHolder = new UserViewHolder(v);
return userViewHolder;
}
@Override
public void onBindViewHolder(UserViewHolder holder, final int position) {
holder.name_entry.setText(mDataSet.get(position).getUser_name());
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onCardClickListner.OnCardClicked(v, position);
}
});
}
@Override
public int getItemCount() {
return mDataSet.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
public static class UserViewHolder extends RecyclerView.ViewHolder {
CardView cardView;
TextView name_entry;
public UserViewHolder(View itemView) {
super(itemView);
cardView = (CardView) itemView.findViewById(R.id.user_layout);
name_entry = (TextView) itemView.findViewById(R.id.name_entry);
}
}
public interface OnCardClickListner {
void OnCardClicked(View view, int position);
}
public void setOnCardClickListner(OnCardClickListner onCardClickListner) {
this.onCardClickListner = onCardClickListner;
}
}
После этого вы получите этот метод переопределения в своей деятельности.
@Override
public void OnCardClicked(View view, int position) {
Log.d("OnClick", "Card Position" + position);
}
Ответ 7
> Как RecyclerView отличается от Listview?
Одно отличие состоит в том, что существует класс LayoutManager
с RecyclerView, с помощью которого вы можете управлять своим RecyclerView
like -
Горизонтальная или вертикальная прокрутка LinearLayoutManager
GridLayout от GridLayoutManager
Разнесенный GridLayout на StaggeredGridLayoutManager
Как для горизонтальной прокрутки для RecyclerView -
LinearLayoutManager llm = new LinearLayoutManager(context);
llm.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(llm);
Ответ 8
Как собрать все вместе...
- обработчик onClick()
- Курсор - RecyclerView
-
Типы ViewHolder
public class OrderListCursorAdapter extends CursorRecyclerViewAdapter<OrderListCursorAdapter.ViewHolder> {
private static final String TAG = OrderListCursorAdapter.class.getSimpleName();
private static final int ID_VIEW_HOLDER_ACTUAL = 0;
private static final int ID_VIEW_HOLDER = 1;
public OrderListCursorAdapter(Context context, Cursor cursor) {
super(context, cursor);
}
public static class ViewHolderActual extends ViewHolder {
private static final String TAG = ViewHolderActual.class.getSimpleName();
protected IViewHolderClick listener;
protected Button button;
public ViewHolderActual(View v, IViewHolderClick listener) {
super(v, listener);
this.listener = listener;
button = (Button) v.findViewById(R.id.orderList_item_button);
button.setOnClickListener(this);
}
public void initFromData(OrderData data) {
Log.d(TAG, "><initFromData(data=" + data + ")");
orderId = data.getId();
vAddressStart.setText(data.getAddressStart());
vAddressEnd.setText(data.getAddressEnd());
}
@Override
public void onClick(View view) {
if (view instanceof Button) {
listener.onButtonClick((Button) view, getPosition(), this);
} else {
super.onClick(view);
}
}
public interface IViewHolderClick extends ViewHolder.IViewHolderClick {
public void onButtonClick(Button button, int position, ViewHolder viewHolder);
}
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private static final String TAG = ViewHolder.class.getSimpleName();
protected long orderId;
protected IViewHolderClick listener;
protected TextView vAddressStart;
protected TextView vAddressEnd;
protected TextView vStatus;
public ViewHolder(View v, IViewHolderClick listener) {
super(v);
this.listener = listener;
v.setOnClickListener(this);
vAddressStart = (TextView) v.findViewById(R.id.addressStart);
vAddressEnd = (TextView) v.findViewById(R.id.addressEnd);
vStatus = (TextView) v.findViewById(R.id.status);
}
public void initFromData(OrderData data) {
Log.d(TAG, "><initFromData(data=" + data + ")");
orderId = data.getId();
vAddressStart.setText(data.getAddressStart());
vAddressEnd.setText(data.getAddressEnd());
}
public long getOrderId() {
return orderId;
}
@Override
public void onClick(View view) {
listener.onCardClick(view, getPosition(), this);
}
public interface IViewHolderClick {
public void onCardClick(View view, int position, ViewHolder viewHolder);
}
}
@Override
public int getItemViewType(int position) {
return position == 0 ? ID_VIEW_HOLDER_ACTUAL : ID_VIEW_HOLDER;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Log.d(TAG, ">>onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")");
ViewHolder result;
switch (viewType) {
case ID_VIEW_HOLDER_ACTUAL: {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout_actual, parent, false);
result = new ViewHolderActual(itemView, new ViewHolderActual.IViewHolderClick() {
@Override
public void onCardClick(View view, int position, ViewHolder viewHolder) {
Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
view.getContext().startActivity(intent);
}
@Override
public void onButtonClick(Button button, int position, ViewHolder viewHolder) {
Log.d(TAG, "><onButtonClick(button=" + button + ", position=" + position + ", viewHolder=" + viewHolder + ")");
Intent intent = new Intent(button.getContext(), OrderMapActivity.class);
intent.putExtra(OrderMapActivity.ARG_ORDER_ID, viewHolder.getOrderId());
button.getContext().startActivity(intent);
}
});
break;
}
case ID_VIEW_HOLDER:
default: {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_layout, parent, false);
result = new ViewHolder(itemView, new ViewHolder.IViewHolderClick() {
@Override
public void onCardClick(View view, int position, ViewHolder viewHolder) {
Log.d(TAG, "><onCardClick(view=" + view + ", position=" + position + ", viewHolder=" + viewHolder + ")");
Intent intent = new Intent(view.getContext(), OrderDetailActivity.class);
intent.putExtra(OrderDetailActivity.ARG_ORDER_ID, viewHolder.getOrderId());
view.getContext().startActivity(intent);
}
});
break;
}
}
Log.d(TAG, "<<onCreateViewHolder(parent=" + parent + ", viewType=" + viewType + ")= " + result);
return result;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, Cursor cursor) {
Log.d(TAG, "><onBindViewHolder(viewHolder=" + viewHolder + ", cursor=" + cursor + ")");
final OrderData orderData = new OrderData(cursor);
viewHolder.initFromData(orderData);
}
}
Ответ 9
Насколько я понимаю ответ MLProgrammer-CiM, просто можно просто сделать это:
class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private ImageView image;
private TextView title;
private TextView price;
public MyViewHolder(View itemView) {
super(itemView);
image = (ImageView)itemView.findViewById(R.id.horizontal_list_image);
title = (TextView)itemView.findViewById(R.id.horizontal_list_title);
price = (TextView)itemView.findViewById(R.id.horizontal_list_price);
image.setOnClickListener(this);
title.setOnClickListener(this);
price.setOnClickListener(this);
}
@Override
public void onClick(View v) {
Toast.makeText(context, "Item click nr: "+getLayoutPosition(), Toast.LENGTH_SHORT).show();
}
}
Ответ 10
Следующее превосходное решение RxJava MLProgrammer-CiM
Потребление/Наблюдение за кликами
ReactiveAdapter rxAdapter = new ReactiveAdapter();
rxAdapter.getPositionClicks().subscribe(mClickConsumer);
Consumer<String> mClickConsumer = new Consumer<String>() {
@Override
public void accept(@NonNull String element) throws Exception {
Toast.makeText(getApplicationContext(), element +" was clicked", Toast.LENGTH_LONG).show();
}
};
RxJava 2. +
Измените оригинал tl; dr как:
public Observable<String> getPositionClicks(){
return onClickSubject;
}
PublishSubject#asObservable()
удален. Просто верните PublishSubject
который является Observable
.
Ответ 11
После прочтения @MLProgrammer-CiM ответа, вот мой код:
class NormalViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
@Bind(R.id.card_item_normal)
CardView cardView;
public NormalViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
cardView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v instanceof CardView) {
// use getAdapterPosition() instead of getLayoutPosition()
int itemPosition = getAdapterPosition();
removeItem(itemPosition);
}
}
}
Ответ 12
Я сделал так, очень просто:
Просто добавьте 1 Строка для Нажмите ссылку RecyclerView:
int position = getLayoutPosition()
Полный код для класса ViewHolder:
private class ChildViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public TextView txtView;
public ChildViewHolder(View itemView) {
super(itemView);
imageView= (ImageView)itemView.findViewById(R.id.imageView);
txtView= (TextView) itemView.findViewById(R.id.txtView);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.i("RecyclerView Item Click Position", String.valueOf(getLayoutPosition()));
}
});
}
}
Надеюсь, это поможет вам.
Ответ 13
Я использую этот метод для запуска Intent из RecyclerView:
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
final MyClass myClass = mList.get(i);
viewHolder.txtViewTitle.setText(myclass.name);
...
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v){
Intent detailIntent = new Intent(mContext, type.class);
detailIntent.putExtra("MyClass", myclass);
mContext.startActivity(detailIntent);
}
}
);
Ответ 14
Вот способ реализовать его довольно легко, если у вас есть список POJO и вы хотите получить один клик извне адаптера.
В вашем адаптере создайте прослушиватель для событий кликов и метод его установки:
public class MyAdapter extends RecyclerView.Adapter<SitesListAdapter.ViewHolder> {
...
private List<MyPojo> mMyPojos;
private static OnItemClickListener mOnItemClickListener;
...
public interface OnItemClickListener {
public void onItemClick(MyPojo pojo);
}
...
public void setOnItemClickListener(OnItemClickListener onItemClickListener){
mOnItemClickListener = onItemClickListener;
}
...
}
В вашем ViewHolder реализовайте onClickListener и создайте члена класса для временного хранения POJO, представляющего это представление (в этом примере лучше создать сеттер):
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public MyPojo mCurrentPojo;
...
public ViewHolder(View view) {
super(v);
...
view.setOnClickListener(this); //You could set this on part of the layout too
}
...
@Override
public void onClick(View view) {
if(mOnItemClickListener != null && mCurrentPojo != null){
mOnItemClickListener.onItemClick(mCurrentPojo);
}
}
Вернитесь в свой адаптер, установите текущее POJO, когда объект ViewHolder привязан (или к null, если текущий вид его не имеет):
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final MyPojo currentPojo = mMyPojos.get(position);
holder.mCurrentPojo = currentPojo;
...
Чтобы это, теперь вы можете использовать его как это из вашего фрагмента/действия:
mMyAdapter.setOnItemClickListener(new mMyAdapter.OnItemClickListener() {
@Override
public void onItemClick(MyPojo pojo) {
//Do whatever you want with your pojo here
}
});
Ответ 15
См. мой подход по этому вопросу:
Сначала объявите интерфейс следующим образом:
/**
* Interface used for delegating item click events in a {@link android.support.v7.widget.RecyclerView}
* Created by Alex on 11/28/2015.
*/
public interface OnRecyclerItemClickListener<T> {
/**
* Called when a click occurred inside a recyclerView item view
* @param view that was clicked
* @param position of the clicked view
* @param item the concrete data that is displayed through the clicked view
*/
void onItemClick(View view, int position, T item);
}
Затем создайте адаптер:
public class CustomRecyclerAdapter extends RecyclerView.Adapter {
private class InternalClickListener implements View.OnClickListener{
@Override
public void onClick(View v) {
if(mRecyclerView != null && mItemClickListener != null){
// find the position of the item that was clicked
int position = mRecyclerView.getChildAdapterPosition(v);
Data data = getItem(position);
// notify the main listener
mItemClickListener.onItemClick(v, position, data);
}
}
}
private final OnRecyclerItemClickListener mItemClickListener;
private RecyclerView mRecyclerView;
private InternalClickListener mInternalClickListener;
/**
*
* @param itemClickListener used to trigger an item click event
*/
public PlayerListRecyclerAdapter(OnRecyclerItemClickListener itemClickListener){
mItemClickListener = itemClickListener;
mInternalClickListener = new InternalClickListener();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item, parent, false);
v.setOnClickListener(mInternalClickListener);
ViewHolder viewHolder = new ViewHolder(v);
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// do your binding here
}
@Override
public int getItemCount() {
return mDataSet.size();
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
mRecyclerView = recyclerView;
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
mRecyclerView = null;
}
public Data getItem(int position){
return mDataset.get(position);
}
}
И теперь посмотрим, как интегрировать это из фрагмента:
public class TestFragment extends Fragment implements OnRecyclerItemClickListener<Data>{
private RecyclerView mRecyclerView;
@Override
public void onItemClick(View view, int position, Data item) {
// do something
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.test_fragment, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mRecyclerView = view.findViewById(idOfTheRecycler);
mRecyclerView .setAdapter(new CustomRecyclerAdapter(this));
}
Ответ 16
RecyclerView не имеет onItemClickListener
потому что RecyclerView отвечает за переработку просмотров (сюрприз!), Поэтому он несет ответственность за представление, которое перерабатывается для обработки событий кликов, которые он получает.
Это на самом деле делает его намного проще в использовании, особенно если у вас есть элементы, которые можно щелкнуть в нескольких местах.
В любом случае, обнаружение щелчка на элементе RecyclerView очень просто. Все, что вам нужно сделать, это определить интерфейс (если вы не используете Kotlin, и в этом случае вы просто проходите в лямбда):
public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
private final Clicks clicks;
public MyAdapter(Clicks clicks) {
this.clicks = clicks;
}
private List<MyObject> items = Collections.emptyList();
public void updateData(List<MyObject> items) {
this.items = items;
notifyDataSetChanged(); // TODO: use ListAdapter for diffing instead if you need animations
}
public interface Clicks {
void onItemSelected(MyObject myObject, int position);
}
public class MyViewHolder extends RecyclerView.ViewHolder {
private MyObject myObject;
public MyViewHolder(View view) {
super(view);
// bind views
view.setOnClickListener((v) -> {
int adapterPosition = getAdapterPosition();
if(adapterPosition >= 0) {
clicks.onItemSelected(myObject, adapterPosition);
}
});
}
public void bind(MyObject myObject) {
this.myObject = myObject;
// bind data to views
}
}
}
Тот же код в Котлине:
class MyAdapter(val itemClicks: (MyObject, Int) -> Unit): RecyclerView.Adapter<MyViewHolder>() {
private var items: List<MyObject> = Collections.emptyList()
fun updateData(items: List<MyObject>) {
this.items = items
notifyDataSetChanged() // TODO: use ListAdapter for diffing instead if you need animations
}
inner class MyViewHolder(val myView: View): RecyclerView.ViewHolder(myView) {
private lateinit var myObject: MyObject
init {
// binds views
myView.onClick {
val adapterPosition = getAdapterPosition()
if(adapterPosition >= 0) {
itemClicks.invoke(myObject, adapterPosition)
}
}
}
fun bind(myObject: MyObject) {
this.myObject = myObject
// bind data to views
}
}
}
Ответ 17
Если вы хотите добавить onClick() в дочерний вид элементов, например кнопку в элементе, я обнаружил, что вы можете сделать это легко в onCreateViewHolder() вашего собственного RecyclerView.Adapter так же:
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater
.from(parent.getContext())
.inflate(R.layout.cell, null);
Button btn = (Button) v.findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do it
}
});
return new MyViewHolder(v);
}
Я не знаю, хороший ли это, но он работает хорошо. Если кто-то имеет лучшую идею, очень рад сказать мне и исправить мой ответ!:)
Ответ 18
Да, вы можете
public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType) {
//inflate the view
View view = LayoutInflator.from(parent.getContext()).inflate(R.layout.layoutID,null);
ViewHolder holder = new ViewHolder(view);
//here we can set onClicklistener
view.setOnClickListener(new View.OnClickListeener(){
public void onClick(View v)
{
//action
}
});
return holder;
Ответ 19
Здесь вы можете обрабатывать несколько onclick, см. ниже код, и это очень эффективно
public class RVNewsAdapter extends RecyclerView.Adapter<RVNewsAdapter.FeedHolder> {
private Context context;
List<News> newsList;
// Allows to remember the last item shown on screen
private int lastPosition = -1;
public RVNewsAdapter(List<News> newsList, Context context) {
this.newsList = newsList;
this.context = context;
}
public static class FeedHolder extends RecyclerView.ViewHolder implements OnClickListener {
ImageView img_main;
TextView tv_title;
Button bt_facebook, bt_twitter, bt_share, bt_comment;
public FeedHolder(View itemView) {
super(itemView);
img_main = (ImageView) itemView.findViewById(R.id.img_main);
tv_title = (TextView) itemView.findViewById(R.id.tv_title);
bt_facebook = (Button) itemView.findViewById(R.id.bt_facebook);
bt_twitter = (Button) itemView.findViewById(R.id.bt_twitter);
bt_share = (Button) itemView.findViewById(R.id.bt_share);
bt_comment = (Button) itemView.findViewById(R.id.bt_comment);
img_main.setOnClickListener(this);
bt_facebook.setOnClickListener(this);
bt_twitter.setOnClickListener(this);
bt_comment.setOnClickListener(this);
bt_share.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if (v.getId() == bt_comment.getId()) {
Toast.makeText(v.getContext(), "Comment " , Toast.LENGTH_SHORT).show();
} else if (v.getId() == bt_facebook.getId()) {
Toast.makeText(v.getContext(), "Facebook " , Toast.LENGTH_SHORT).show();
} else if (v.getId() == bt_twitter.getId()) {
Toast.makeText(v.getContext(), "Twitter " , Toast.LENGTH_SHORT).show();
} else if (v.getId() == bt_share.getId()) {
Toast.makeText(v.getContext(), "share " , Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(v.getContext(), "ROW PRESSED = " + String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
}
@Override
public FeedHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.feed_row, parent, false);
FeedHolder feedHolder = new FeedHolder(view);
return feedHolder;
}
@Override
public void onBindViewHolder(FeedHolder holder, int position) {
holder.tv_title.setText(newsList.get(position).getTitle());
// Here you apply the animation when the view is bound
setAnimation(holder.img_main, position);
}
@Override
public int getItemCount() {
return newsList.size();
}
/**
* Here is the key method to apply the animation
*/
private void setAnimation(View viewToAnimate, int position) {
// If the bound view wasn't previously displayed on screen, it animated
if (position > lastPosition) {
Animation animation = AnimationUtils.loadAnimation(context, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
lastPosition = position;
}
}
}
Ответ 20
Изменен мой комментарий...
public class MyViewHolder extends RecyclerView.ViewHolder {
private Context mContext;
public MyViewHolder(View itemView) {
super(itemView);
mContext = itemView.getContext();
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int itemPosition = getLayoutPosition();
Toast.makeText(mContext, "" + itemPosition, Toast.LENGTH_SHORT).show();
}
});
}
Ответ 21
Проверьте это, в котором я правильно использовал все вещи
Класс RecyclerViewHolder
public class RecyclerViewHolder extends RecyclerView.ViewHolder {
//view holder is for girdview as we used in the listView
public ImageView imageView,imageView2;
public RecyclerViewHolder(View itemView) {
super(itemView);
this.imageView=(ImageView)itemView.findViewById(R.id.image);
}
}
Адаптер
public class RecyclerView_Adapter extends RecyclerView.Adapter<RecyclerViewHolder> {
//RecyclerView will extend to recayclerview Adapter
private ArrayList<ModelClass> arrayList;
private Context context;
private static RecyclerViewClickListener itemListener;
//constructor of the RecyclerView Adapter
RecyclerView_Adapter(Context context,ArrayList<ModelClass> arrayList,RecyclerViewClickListener itemListener){
this.context=context;
this.arrayList=arrayList;
this.itemListener=itemListener;
}
@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//this method will inflate the custom layout and return as viewHolder
LayoutInflater layoutInflater=LayoutInflater.from(parent.getContext());
ViewGroup mainGroup=(ViewGroup) layoutInflater.inflate(R.layout.single_item,parent,false);
RecyclerViewHolder listHolder=new RecyclerViewHolder(mainGroup);
return listHolder;
}
@Override
public void onBindViewHolder(RecyclerViewHolder holder, final int position) {
final ModelClass modelClass=arrayList.get(position);
//holder
RecyclerViewHolder mainHolder=(RecyclerViewHolder)holder;
//convert the drawable image into bitmap
Bitmap image= BitmapFactory.decodeResource(context.getResources(),modelClass.getImage());
//set the image into imageView
mainHolder.imageView.setImageBitmap(image);
//to handle on click event when clicked on the recyclerview item and
// get it through the RecyclerViewHolder class we have defined the views there
mainHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//get the position of the image which is clicked
itemListener.recyclerViewListClicked(v,position);
}
});
}
@Override
public int getItemCount() {
return (null!=arrayList?arrayList.size():0);
}
}
Интерфейс
public interface RecyclerViewClickListener {
//this is method to handle the event when clicked on the image in Recyclerview
public void recyclerViewListClicked(View v,int position);
}
//and to call this method in activity
RecyclerView_Adapter adapter=new RecyclerView_Adapter(Wallpaper.this,arrayList,this);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
@Override
public void recyclerViewListClicked(View v,int position){
imageView.setImageResource(wallpaperImages[position]);
}
Ответ 22
Это сработало для меня:
@Override
public void onBindViewHolder(PlacesListViewAdapter.ViewHolder holder, int position) {
----
----
----
// Set setOnClickListener(holder);
}
@Override
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
----
----
----
@Override
public void onClick(View view) {
// Use to get the item clicked getAdapterPosition()
}
}
Ответ 23
Доступ к mainView
rowLayout(cell)
для вас RecyclerView
и в OnBindViewHolder
введите этот код:
@Override
public void onBindViewHolder(MyViewHolder holder, final int position) {
Movie movie = moviesList.get(position);
holder.mainView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
System.out.println("pos " + position);
}
});
}
Ответ 24
это сработало для меня. Надеюсь, это поможет. Самый простой способ.
Держатель внутреннего вида
class GeneralViewHolder extends RecyclerView.ViewHolder {
View cachedView = null;
public GeneralViewHolder(View itemView) {
super(itemView);
cachedView = itemView;
}
Внутри OnBindViewHolder()
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final GeneralViewHolder generalViewHolder = (GeneralViewHolder) holder;
generalViewHolder.cachedView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, "item Clicked at "+position, Toast.LENGTH_SHORT).show();
}
});
И дайте мне знать, есть ли у вас какие-либо вопросы по поводу этого решения?
Ответ 25
main_recyclerview.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
int position=rv.getChildAdapterPosition(rv.findChildViewUnder(e.getX(),e.getY()));
switch (position)
{
case 0:
{
wifi(position);
adapter2.notifyDataSetChanged();
}
break;
case 1:
{
sound(position);
adapter2.notifyDataSetChanged();
}
break;
case 2:
{
bluetooth(position);
adapter2.notifyDataSetChanged();
}
break;
}
return true;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e)
{
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
Ответ 26
Вместо того, чтобы реализовывать интерфейс View.OnClickListener внутри владельца или создавать интерфейс и реализовывать интерфейс в вашей деятельности.
Я использовал этот код для простого в реализации OnClickListener.
public static class SimpleStringRecyclerViewAdapter
extends RecyclerView.Adapter<SimpleStringRecyclerViewAdapter.ViewHolder> {
// Your initializations goes here...
private List<String> mValues;
public static class ViewHolder extends RecyclerView.ViewHolder {
//create a variable mView
public final View mView;
/*All your row widgets goes here
public final ImageView mImageView;
public final TextView mTextView;*/
public ViewHolder(View view) {
super(view);
//Initialize it here
mView = view;
/* your row widgets initializations goes here
mImageView = (ImageView) view.findViewById(R.id.avatar);
mTextView = (TextView) view.findViewById(android.R.id.text1);*/
}
}
public String getValueAt(int position) {
return mValues.get(position);
}
public SimpleStringRecyclerViewAdapter(Context context, List<String> items) {
mBackground = mTypedValue.resourceId;
mValues = items;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
view.setBackgroundResource(mBackground);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.mBoundString = mValues.get(position);
holder.mTextView.setText(mValues.get(position));
//Here it is simply write onItemClick listener here
holder.mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Context context = v.getContext();
Intent intent = new Intent(context, ExampleActivity.class);
context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mValues.size();
}
}
Ответ 27
использовать PlaceHolderView
@Layout(R.layout.item_view_1)
public class View1{
@View(R.id.txt)
public TextView txt;
@Resolve
public void onResolved() {
txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
}
@Click(R.id.btn)
public void onClick(){
txt.setText(String.valueOf(System.currentTimeMillis() / 1000));
}
}
Ответ 28
Я написал библиотеку для обработки события щелчка элемента просмотра андроид-ресайклера. Вы можете найти полный учебник в https://github.com/ChathuraHettiarachchi/RecycleClick
RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemClickListener(new RecycleClick.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
}
});
или для обработки длинного нажатия элемента вы можете использовать
RecycleClick.addTo(YOUR_RECYCLEVIEW).setOnItemLongClickListener(new RecycleClick.OnItemLongClickListener() {
@Override
public boolean onItemLongClicked(RecyclerView recyclerView, int position, View v) {
// YOUR CODE
return true;
}
});
Ответ 29
анимация recyclerview не тестировалась, другая - обычная. Я думаю, что он был оптимизирован до максимума. Интерфейс имеет другое использование, вы можете временно игнорировать.
public abstract class BaseAdapterRV<VH extends BaseViewHolder> extends RecyclerView.Adapter<VH> implements AdapterInterface {
public final String TAG = getClass().getSimpleName();
protected final Activity mActivity;
protected final LayoutInflater mInflater;
protected ItemClickInterface<?, Integer> mListener;
public BaseAdapterRV(Activity activity) {
mActivity = activity;
mInflater = LayoutInflater.from(mActivity);
}
@Override
public final VH onCreateViewHolder(ViewGroup parent, int viewType) {
return onCreateViewHolder(parent, viewType, mInflater);
}
@Override
public final void onBindViewHolder(VH holder, int position) {
holder.itemView.setTag(R.id.tag_view_click, position);
//创建点击事件
holder.itemView.setOnClickListener(mListener);
holder.itemView.setOnLongClickListener(mListener);
onBindVH(holder, position);
}
///////////////////////////////////////////////////////////////////////////
// 以下是增加的方法
///////////////////////////////////////////////////////////////////////////
/**
* 注意!涉及到notifyItemInserted刷新时立即获取position可能会不正确
* 里面也有onItemLongClick
*/
public void setOnItemClickListener(ItemClickInterface<?, Integer> listener) {
mListener = listener;
notifyDataSetChanged();
}
@NonNull
protected abstract VH onCreateViewHolder(ViewGroup parent, int viewType, LayoutInflater inflater);
protected abstract void onBindVH(VH holder, int position);
}
Это интерфейс
/**
* OnItemClickListener的接口
* 见子类实现{@link OnItemClickListener}{@link OnItemItemClickListener}
*/
public interface ItemClickInterface<DATA1, DATA2> extends View.OnClickListener, View.OnLongClickListener {
void onItemClick(DATA1 data1, DATA2 data2);
boolean onItemLongClick(DATA1 data1, DATA2 data2);
}
Это абстрактный класс
public abstract class OnItemClickListener<DATA> implements ItemClickInterface<View, DATA> {
@Override
public void onClick(View v) {
onItemClick(v, (DATA) v.getTag(R.id.tag_view_click));
}
@Override
public boolean onLongClick(View v) {
return onItemLongClick(v, (DATA) v.getTag(R.id.tag_view_click));
}
@Override
public boolean onItemLongClick(View view, DATA data) {
return false;
}
}
Вам это нужно только
mAdapter.setOnItemClickListener(new OnItemClickListener<Integer>() {
@Override
public void onItemClick(View view, Integer integer) {
}
@Override
public boolean onItemLongClick(View view, Integer integer) {
return true;
}
});
Ответ 30
Мне нравится этот способ, и я им пользуюсь
внутри
public Adapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
Положил
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_image_and_text, parent, false);
v.setOnClickListener(new MyOnClickListener());
И создайте этот класс где угодно
class MyOnClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
int itemPosition = recyclerView.indexOfChild(v);
Log.e("Clicked and Position is ",String.valueOf(itemPosition));
}
}
Я читал ранее, что есть лучший способ, но мне нравится этот путь легкий и не сложный. Я надеюсь, что это поможет вам..!