RecyclerView onClick
Кто-нибудь использует RecyclerView
нашел способ установить onClickListener
к предметам в RecyclerView
? Я думал о том, чтобы настроить слушателя для каждого макета для каждого элемента, но это кажется слишком сложным, я уверен, что есть способ для RecyclerView
слушать за onClick
событие, но я не могу понять это.
49 ответов
Поскольку API радикально изменились, меня не удивит, если вы создадите OnClickListener
за каждый предмет. Это не так много хлопот, хотя. В вашей реализации RecyclerView.Adapter<MyViewHolder>
, у тебя должно быть:
private final OnClickListener mOnClickListener = new MyOnClickListener();
@Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.myview, parent, false);
view.setOnClickListener(mOnClickListener);
return new MyViewHolder(view);
}
onClick
метод:
@Override
public void onClick(final View view) {
int itemPosition = mRecyclerView.getChildLayoutPosition(view);
String item = mList.get(itemPosition);
Toast.makeText(mContext, item, Toast.LENGTH_LONG).show();
}
Вот лучший и менее тесно связанный способ реализации OnClickListener
для RecyclerView
,
Фрагмент использования:
RecyclerView recyclerView = findViewById(R.id.recycler);
recyclerView.addOnItemTouchListener(
new RecyclerItemClickListener(context, recyclerView ,new RecyclerItemClickListener.OnItemClickListener() {
@Override public void onItemClick(View view, int position) {
// do whatever
}
@Override public void onLongItemClick(View view, int position) {
// do whatever
}
})
);
RecyclerItemClickListener
реализация:
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);
public void onLongItemClick(View view, int position);
}
GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && mListener != null) {
mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
}
}
});
}
@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 true;
}
return false;
}
@Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }
@Override
public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
}
Я делаю это таким образом, без лишних классов, детекторов и т. Д. Простой код внутри нашего адаптера. Особенно лучшее решение для longClick, чем представленное ранее.
public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> {
private static ClickListener clickListener;
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView name;
public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
name = (TextView) itemView.findViewById(R.id.card_name);
}
@Override
public void onClick(View v) {
clickListener.onItemClick(getAdapterPosition(), v);
}
@Override
public boolean onLongClick(View v) {
clickListener.onItemLongClick(getAdapterPosition(), v);
return false;
}
}
public void setOnItemClickListener(ClickListener clickListener) {
PasswordAdapter.clickListener = clickListener;
}
public interface ClickListener {
void onItemClick(int position, View v);
void onItemLongClick(int position, View v);
}
}
Затем внутри фрагмента или действия просто нажмите:
PasswordAdapter mAdapter = ...;
mAdapter.setOnItemClickListener(new PasswordAdapter.ClickListener() {
@Override
public void onItemClick(int position, View v) {
Log.d(TAG, "onItemClick position: " + position);
}
@Override
public void onItemLongClick(int position, View v) {
Log.d(TAG, "onItemLongClick pos = " + position);
}
});
Посмотрите похожий вопрос @CommonsWare в комментариях к этому, который реализует OnClickListener
интерфейс в viewHolder
,
Вот простой пример ViewHolder
:
TextView textView;//declare global with in adapter class
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
textView = (TextView)view.findViewById(android.R.id.text1);
}
@Override
public void onClick(View view) {
Toast.makeText(view.getContext(), "position = " + getLayoutPosition(), Toast.LENGTH_SHORT).show();
//go through each item if you have few items within recycler view
if(getLayoutPosition()==0){
//Do whatever you want here
}else if(getLayoutPosition()==1){
//Do whatever you want here
}else if(getLayoutPosition()==2){
}else if(getLayoutPosition()==3){
}else if(getLayoutPosition()==4){
}else if(getLayoutPosition()==5){
}
//or you can use For loop if you have long list of items. Use its length or size of the list as
for(int i = 0; i<exampleList.size(); i++){
}
}
}
Adapter
тогда выглядит так:
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view =LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
return new ViewHolder(view);
}
Основываясь на ответе Джейкоба Табака (+1 для него), я смог добавить слушателя onLongClick:
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 {
public interface OnItemClickListener {
void onItemClick(View view, int position);
void onItemLongClick(View view, int position);
}
private OnItemClickListener mListener;
private GestureDetector mGestureDetector;
public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
mListener = listener;
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (childView != null && mListener != null) {
mListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView));
}
}
});
}
@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.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
// ...
}
@Override
public void onItemLongClick(View view, int position) {
// ...
}
}));
Это то, что сработало для меня. Прикрепить OnClickListener
к onBindView
, На самом деле я не знаю, повлияет ли это на производительность, но, похоже, с небольшим кодом все работает нормально.
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(context, "Recycle Click" + position, Toast.LENGTH_SHORT).show();
}
});
}
Мне было так трудно иметь прослушиватель щелчков по элементам в упражнении, а также иметь прослушиватель щелчков для одного представления элемента, которое не будет вызывать прослушиватель щелчков по элементам. После игры с ответом Джейкоба Табака я уважаю его ответ на щелчок предмета, если внутри предмета не представлено никаких других действий касания.
У меня есть обычай OnClickListener
интерфейс, который имеет событие щелчка элемента, которое содержит вид элемента, по которому щелкнули, и позицию элемента из адаптера. Я представляю экземпляр этого в конструкторе (или это может быть с сеттером) и присоединяю его к слушателю щелчка контейнера контейнера представления.
У меня также есть другой прослушиватель щелчков в адаптере (может быть в держателе вида), который будет обрабатывать текущий щелчок вида из контейнера.
public class MyRecyclerAdapter extends RecyclerView.Adapter<MyViewHolder> {
private ArrayList<String> mData;
private OnItemClickListener mOnItemClickListener;
public interface OnItemClickListener {
public void onItemClick(View view, int position);
}
public MyRecyclerAdapter(ArrayList<String> itemsData,
OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
this.mData = itemsData;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View layoutView = LayoutInflater.from(mContext).inflate(
R.layout.list_item, parent, false);
MyViewHolder viewHolder = new MyViewHolder(layoutView);
return viewHolder;
}
@Override
public void onBindViewHolder(MyViewHolder viewHolder,
final int position) {
viewHolder.container.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mOnItemClickListener.onItemClick(v, position);
}
});
viewHilder.button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//do button click work here
}
});
}
@Override
public int getItemCount() {
return mData.size();
}}
В упражнении нужно инициализировать адаптер, передав экземпляр OnItemClickListener
public class FeedActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
.....
MyRecyclerAdapter adapter = new MyRecyclerAdapter(new ArrayList<String>(), new OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
///list item was clicked
}
});
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(mFeedsAdapter);
}
И мой ViewHolder
public class MyViewHolder extends RecyclerView.ViewHolder {
public Button button;
public View container;
public MyViewHolder(View itemLayoutView) {
super(itemLayoutView);
container = itemLayoutView;
button = (Button) itemLayoutView.findViewById(R.id.button);
}}
Это то, что мне в конечном итоге нужно, на случай, если кто-то найдет это полезным:
public static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View item) {
super(item);
item.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("RecyclerView", "onClick:" + getAdapterPosition());
}
});
}
}
Источник: http://blog.csdn.net/jwzhangjie/article/details/36868515
У меня есть хорошее решение для RecyclerView
"s onItemClickListener
для предметов и подпунктов
Шаг 1- Создать интерфейс
public interface OnRecyclerViewItemClickListener
{
/**
* Called when any item with in recyclerview or any item with in item
* clicked
*
* @param position
* The position of the item
* @param id
* The id of the view which is clicked with in the item or
* -1 if the item itself clicked
*/
public void onRecyclerViewItemClicked(int position, int id);
}
Шаг 2- Затем используйте его в адаптере onBindViewHolder
метод следующим образом
/**
* Custom created method for Setting the item click listener for the items and items with in items
* @param listener OnRecyclerViewItemClickListener
*/
public void setOnItemClickListener(OnRecyclerViewItemClickListener listener)
{
this.listener = listener;
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, final int position)
{
// viewHolder.albumBg.setBackgroundResource(_itemData[position]
// .getImageUrl());
viewHolder.albumName.setText(arrayList.get(position).getName());
viewHolder.artistName.setText(arrayList.get(position).getArtistName());
String imgUrl = arrayList.get(position).getThumbImageUrl();
makeImageRequest(imgUrl, viewHolder);
viewHolder.parentView.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
listener.onRecyclerViewItemClicked(position, -1);
}
});
viewHolder.settingButton.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
listener.onRecyclerViewItemClicked(position, v.getId());
}
});
}
// class to hold a reference to each item of RecyclerView
public static class ViewHolder extends RecyclerView.ViewHolder
{
public TextView albumName, artistName;
public ImageView albumIcon, settingButton;
public LinearLayout parentView;
public ViewHolder(View itemLayoutView)
{
super(itemLayoutView);
// albumBg = (LinearLayout) itemLayoutView
// .findViewById(R.id.albumDlbg);
albumName = (TextView) itemLayoutView.findViewById(R.id.albumName);
artistName = (TextView) itemLayoutView
.findViewById(R.id.artistName);
albumIcon = (ImageView) itemLayoutView.findViewById(R.id.albumIcon);
parentView = (LinearLayout) itemLayoutView
.findViewById(R.id.albumDlbg);
settingButton = (ImageView) itemLayoutView
.findViewById(R.id.settingBtn);
}
}
Шаг 3- найдите и настройте представление рециркулятора в действии или фрагменте, где вы используете это
recyclerView = (RecyclerView) rootview.findViewById(R.id.vmtopsongs);
lm = new LinearLayoutManager(mActivity);
lm.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(lm);
recyclerView.addItemDecoration(
new HorizontalDividerItemDecoration.Builder(getActivity())
.paint(Utils.getPaint()).build());
PopularSongsadapter mAdapter = new PopularSongsadapter(gallery,
mActivity, true);
// set adapter
recyclerView.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(this);
// set item animator to DefaultAnimator
recyclerView.setItemAnimator(new DefaultItemAnimator());
Шаг 4- Наконец-то внедрите интерфейс в действие или фрагмент, где вы используете просмотрщик
@Override
public void onRecyclerViewItemClicked(int position, int id)
{
if(id==-1){
Toast.makeText(mActivity, "complete item clicked", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(mActivity, "setting button clicked", Toast.LENGTH_LONG).show();
}
}
Вот что я сделал. Это решение поддерживает как onClick, так и onLongClick для элементов RecyclerView и представлений внутри элементов RecyclerView (внутренние представления).
Я отмечаю viewHolder на представлениях по моему выбору:
public RecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item, null);
ViewHolder viewHolder = new ViewHolder(itemView);
itemView.setOnClickListener( this);
itemView.setOnLongClickListener(this);
viewHolder.imageIV.setOnClickListener(this);
viewHolder.imageIV.setOnLongClickListener(this);
viewHolder.imageIV.setTag(viewHolder);
itemView.setTag(viewHolder);
return viewHolder;
}
И я использую holder.getPosition () для получения позиции в методе onClick () (onLongClick аналогично):
public void onClick(View view) {
ViewHolder holder = (ViewHolder) view.getTag();
int position = holder.getPosition();
if (view.getId() == holder.imageIV.getId()){
Toast.makeText(context, "imageIV onClick at" + position, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(context, "RecyclerView Item onClick at " + position, Toast.LENGTH_SHORT).show();
}
}
Вариант с getChildPosition также работает. Обратите внимание, что для внутренних представлений в onClick () используйте:
int position = recyclerView.getChildPosition((View)view.getParent());
На мой взгляд, преимущество этого решения заключается в том, что при нажатии на изображение вызывается только прослушиватель изображения onclick (), тогда как при объединении решения Jacob для представления элемента RecyclerView и моего решения для внутренних представлений представление RecyclerView Item onclick () также называется (при нажатии на изображение).
Существует гораздо более простой способ сделать это. Просто подать заявку на клик в onBindViewHolder
на корневой вид.
Считайте, что это ваш взгляд на адаптер,
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="1dp"
android:textSize="15sp" />
</LinearLayout>
Затем выполните следующее в вашем адаптере
//get the layout and make view holder
@Override
public RVAdapter.ViewHolder1 onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_layout, null);
ViewHolder1 viewHolder = new ViewHolder1(view);
return viewHolder;
}
@Override
public void onBindViewHolder(RVAdapter.ViewHolder1 holder, int position) {
//apply on click on your root view
holder.linearlayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Do on click stuff
}
});
}
//make references to views in layout including root view
public class ViewHolder1 extends RecyclerView.ViewHolder {
protected LinearLayout linearlayout = null
protected TextView textview = null;
public CareerLinksViewHolder(View itemView) {
super(itemView);
this.linearlayout = (LinearLayout) itemView.findViewById(R.id.linearlayout);
this.tvCompName = (TextView) itemView.findViewById(R.id.textview);
}
}
Вы можете передать clickListener
в Adapter
,
В вашем Activity
:
private View.OnClickListener mItemClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = null;
int position = list.getChildPosition(v);
switch (position) {
case 0:
intent = new Intent(MainActivity.this, LeakCanaryActivity.class);
break;
case 1:
intent = new Intent(MainActivity.this, ButterKnifeFragmentActivity.class);
break;
}
if (intent != null) {
MainActivity.this.startActivity(intent);
}
}
};
затем передать его Adapter
:
MainAdapter mainAdapter = new MainAdapter(this, mItemClick);
В Adapter
"s onCreateViewHolder
:
@Override
public MainAdapter.ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
View itemView = activity.getLayoutInflater().inflate(R.layout.main_adapter_item, viewGroup, false);
ViewHolder holder = new ViewHolder(itemView);
itemView.setOnClickListener(mItemClick);
return holder;
}
Я разработал облегченную библиотеку для Android, вы можете посетить 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
}
});
Слишком просто и эффективно.
Вместо реализации интерфейса 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();
}
}
Если вы хотите отловить событие клика по отдельным элементам, просто внедрите OnClickListener
в ViewHolder
класс, а затем установить слушателей щелчка на отдельных представлениях или целом itemView
,
Следующий пример показывает то же самое
public class ContactViewHolder extends RecyclerView.ViewHolder implements OnClickListener
{
TextView txt_title,txt_name,txt_email;
public ContactViewHolder(View itemView)
{
super(itemView);
txt_title = (TextView)itemView.findViewById(R.id.txt_title);
txt_name = (TextView)itemView.findViewById(R.id.txt_name);
txt_email = (TextView)itemView.findViewById(R.id.txt_email);
txt_name.setOnClickListener(this);
txt_email.setOnClickListener(this);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v == itemView)
{
Toast.makeText(RecyclerDemoActivity.this, "Visiting Card Clicked is ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
}
if(v == txt_name)
{
Toast.makeText(RecyclerDemoActivity.this, "Name ==>"+txt_name.getText(), Toast.LENGTH_SHORT).show();
}
if(v == txt_email)
{
Toast.makeText(RecyclerDemoActivity.this, "Email ==>"+txt_email.getText(), Toast.LENGTH_SHORT).show();
}
}
}
}
Вы можете реализовать OnClickListener для вашего класса ViewHolder
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public Item item
@InjectView(R.id.tv_title)
public TextView tvTitle;
@InjectView(R.id.rl_row)
public RelativeLayout rlRow;
public ViewHolder(View v) {
super(v);
ButterKnife.inject(this, v);
v.setOnClickListener(this);
}
@Override
public void onClick(View view) {
Log.e("item title",item.getTitle());
}
}
И onBindViewHolder установить элемент вашего держателя представления
public void onBindViewHolder(ViewHolder holder, int position) {
holder.tvTitle.setText(objects.get(position).getTitle());
holder.item = objects.get(position);
}
По словам Йигита Бояра, лучший способ зарегистрировать щелчок по RecyclerView - это определить щелчок при создании держателя просмотра, а не просто создавать новый onClickListener для каждого элемента, которыйonBindViewHolder
связывает
пример
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
val itemBinding = LayoutInflater.from(context).inflate(R.layout.my_layout, parent, false)
val vh = MainViewHolder(itemBinding)
vh.itemView.setOnClickListener {
val pos = vh.adapterPosition
if(pos != NO_POSITION){
itemClickLister.onCocktailClick(myList[pos],pos)
}
}
return vh
}
Все ответы, опубликованные до сих пор, являются отличными решениями, однако, если вы не хотите иметь дело со слишком большим количеством деталей реализации и просто хотите, чтобы он работал аналогично ListView, я бы порекомендовал использовать TwoWay-View, как показано здесь:
https://github.com/lucasr/twoway-view
Обратите внимание, что эта реализация также поддерживает длительное нажатие на элементы, а также поддержку нажатых состояний (что является важным, чего нет в других решениях этого вопроса).
Если вы не хотите использовать всю библиотеку, взгляните на класс ClickItemTouchListener, который при необходимости можно использовать как самостоятельный. Единственная проблема, с которой я столкнулся на данный момент - это долгое нажатие + прокрутка, похоже, некорректное поведение.
Вы можете легко определить setOnClickListener в вашем классе ViewHolder следующим образом:
public class ViewHolder extends RecyclerView.ViewHolder {
TextView product_name;
ViewHolder(View itemView) {
super(itemView);
product_name = (TextView) itemView.findViewById(R.id.product_name);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int itemPosition = getLayoutPosition();
Toast.makeText(getApplicationContext(), itemPosition + ":" + String.valueOf(product_name.getText()), Toast.LENGTH_SHORT).show();
}
});
}
}
Для меня это лучший способ:
class YourRecyclerAdapter extends RecyclerView.Adapter<ContactViewHolder> implements View.OnClickListener {
...
@Override
public void onClick(View view) {
int itemPosition = vRecycle.getChildPosition(view);
//And use itemPosition to get the item from your collection. This way you dont restrain the ViewHolder with a OnClick callback
}
...
}
Kotlin реализация ответа nhaarman:
mRecyclerView.addOnItemTouchListener(object : RecyclerItemClickListener(this, mRecyclerView,object :RecyclerItemClickListener.OnItemClickListener{
override fun onItemClick(view: View, position: Int) {
}
override fun onLongItemClick(view: View?, position: Int) {
}
}){})
RecyclerItemClickListener.java:
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
open class RecyclerItemClickListener(context: Context, recyclerView: RecyclerView, private val mListener: OnItemClickListener?) : RecyclerView.OnItemTouchListener {
private var mGestureDetector: GestureDetector
interface OnItemClickListener {
fun onItemClick(view: View, position: Int)
fun onLongItemClick(view: View?, position: Int)
}
init {
mGestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(e: MotionEvent): Boolean {
return true
}
override fun onLongPress(e: MotionEvent) {
val child = recyclerView.findChildViewUnder(e.x, e.y)
if (child != null && mListener != null) {
mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child))
}
}
})
}
override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean {
val childView = view.findChildViewUnder(e.x, e.y)
if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
mListener.onItemClick(childView, view.getChildAdapterPosition(childView))
return true
}
return false
}
override fun onTouchEvent(view: RecyclerView, motionEvent: MotionEvent) {}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
}
Вот что я сделал Подробнее и скачать суть здесь
Добавление того же здесь
CustomItemClickListener.java
public interface CustomItemClickListener {
public void onItemClick(View v, int position);
}
ItemsListAdapter.java
public class ItemsListAdapter extends RecyclerView.Adapter<ItemsListAdapter.ViewHolder> {
ArrayList<ItemListSingleItem> data;
Context mContext;
CustomItemClickListener listener;
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View mView = LayoutInflater.from(parent.getContext()).inflate(R.layout.items_list_single_item, parent, false);
final ViewHolder mViewHolder = new ViewHolder(mView);
mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onItemClick(v, mViewHolder.getPosition());
}
});
return mViewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.itemTitle.setText(Html.fromHtml(data.get(position).getTitle()));
if (!TextUtils.isEmpty(data.get(position).getThumbnailURL())) {
// I Love picasso library :) http://square.github.io/picasso/
Picasso.with(mContext).load(data.get(position).getThumbnailURL()).error(R.drawable.ic_no_image).
placeholder(R.drawable.ic_no_image).
transform(new RoundedCornersTransformation(5, 0)).
into(holder.thumbnailImage);
} else {
holder.thumbnailImage.setImageResource(R.drawable.ic_no_image);
}
}
@Override
public int getItemCount() {
return data.size();
}
public ItemsListAdapter(Context mContext, ArrayList<ItemsListSingleItem> data, CustomItemClickListener listener) {
this.data = data;
this.mContext = mContext;
this.listener = listener;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView itemTitle;
public ImageView thumbnailImage;
ViewHolder(View v) {
super(v);
itemTitle = (TextView) v
.findViewById(R.id.post_title);
thumbnailImage = (ImageView) v.findViewById(R.id.post_thumb_image);
}
}
}
RecyclerView
не имеет OnClickListener
и придется реализовать это самим.
Мне нравится добавлять OnItemClickListener
интерфейс в Adapter
с onClick
метод вызывается при нажатии на вид элемента из ViewHolder
, Таким образом, ответственность за управление кликом на элементе лежит вне ViewHolder
а также Adapter
, Будет ли действие или фрагмент, который будет решать, что делать
Добавьте интерфейс к слушателю и объекту слушателя.
public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ViewHolder> {
...
private static OnItemClickListener onItemClickListener;
...
public static interface OnItemClickListener {
public void onItemClick(View view, int position);
}
...
}
Мы фиксируем щелчок в корневом представлении элемента и при запуске обратного вызова onClick
вызов слушателя на адаптере.
public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ViewHolder> {
...
private static OnItemClickListener onItemClickListener;
...
public static interface OnItemClickListener {
public void onItemClick(View view, int position);
}
...
public static class ViewHolder extends RecyclerView.ViewHolder {
public ImageView imageView;
public ViewHolder(View itemRootView) {
super(itemRootView);
imageView = (ImageView) itemRootView.findViewById(R.id.itemImage);
itemRootView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = ViewHolder.super.getAdapterPosition();
onItemClickListener.onItemClick(view,position);
}
});
}
}
}
Так как в нашем случае активность или фрагмент, фрагмент в нашем случае, мы назначаем слушателю для адаптера, а с помощью обратного вызова onClick мы получим выбранный элемент по позиции и открыли подробную активность элемента.
public class ItemsFragment extends Fragment {
...
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
((ItemsAdapter) adapter).setOnItemClickListener(new ItemsAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
//Do something when an item has been clicked
}
});
...
}
...
}
К несчастью RecyclerView
отсутствует пара функций, которые ListView
был встроен. Например, возможность добавить OnItemClickListener
это срабатывает при нажатии на элемент. RecyclerView
позволяет установить OnClickListener
в вашем адаптере, но передавая этот прослушиватель щелчка от вашего вызывающего кода к адаптеру и к ViewHolder
, сложен для ловли простого клика элемента.
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) {
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) {
if (mOnItemClickListener != null) {
view.setOnClickListener(mOnClickListener);
}
if (mOnItemLongClickListener != null) {
view.setOnLongClickListener(mOnLongClickListener);
}
}
@Override
public void onChildViewDetachedFromWindow(View view) {
}
};
private ItemClickSupport(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
mRecyclerView.setTag(R.id.item_click_support, this);
mRecyclerView.addOnChildAttachStateChangeListener(mAttachListener);
}
public static ItemClickSupport addTo(RecyclerView view) {
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);
}
}
Вы также должны определить R.id.item_click_support
используя ids.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="item_click_support" type="id" />
</resources>
Получившийся код прослушивания кликов теперь выглядит так:
ItemClickSupport.addTo(mRecyclerView).setOnItemClickListener(new ItemClickSupport.OnItemClickListener() {
@Override
public void onItemClicked(RecyclerView recyclerView, int position, View v) {
// do it
}
});
Для краткого объяснения о кликах в обзоре переработчика, пожалуйста, посмотрите этот littlerobots_blog
Судя по большинству приведенных выше ответов, они, похоже, устанавливают свои onclicklisteners для отдельных элементов. Тем не менее, решение, которое я собираюсь предложить, очень простое, но не интуитивно понятное для многих. Многие забывают, что другие компоненты всегда находятся в родительском компоненте, который используется для отображения элементов в представлениях List или Recycler. Это решение заключается только в том, чтобы настроить одного слушателя onclick для этого родительского представления, и ход проигрывается. Решение также включает в себя способ передачи позиции, по которой щелкают элементы, из списка или представления переработчика. Здесь наш основной rootview - это CardView из библиотеки поддержки Android. Вот пример кода
public class ListAdapter extends RecyclerView.Adapter<ListAdapter.ViewHolder> {
public static final String LOG_TAG = ListAdapter.class.getSimpleName();
private Cursor mDataset;
private Context mContext;
private ViewHolder mViewHolder;
// Provide a suitable constructor (depends on the kind of dataset)
public ListAdapter(Context context, Cursor Dataset) {
mDataset = Dataset;
mContext = context;
}
// Create new views (invoked by the layout manager)
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_business_view, parent, false);
mViewHolder = new ViewHolder(v);
return mViewHolder;
}
public void setData(Cursor newdata) {
this.mDataset = newdata;
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//Bind data to other items here. To save time, i have ommited that.
//here is where we attach a click listerner for an item in the recycler list rather than for each element of a given item.
holder.card.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext, " Just cliked item at position " + itemPosition, Toast.LENGTH_LONG).show();
}
});
}
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
if (null != mDataset) {
return mDataset.getCount();
}
return 0;
}
// Provide a reference to the views for each data item
// Complex data items may need more than one view per item, and
// you provide access to all the views for a data item in a view holder
public static class ViewHolder extends RecyclerView.ViewHolder{
// each data item is just a string in this case
public final TextView mBusinesssName; // View for the business name
public final TextView mBusinessCategory; //View for the category name
public final ImageView businessImage; // View for the business category image Image
public final TextView mBusinessDistance; // View for the distance
public final CardView card;
public ViewHolder(View view) {
super(view);
mBusinesssName = (TextView) view.findViewById(R.id.list_item_name_textview);
mBusinessCategory = (TextView) view.findViewById(R.id.list_item_category_textview);
mBusinessDistance = (TextView) view.findViewById(R.id.list_item_dist_textview);
businessImage = (ImageView) view.findViewById(R.id.list_item_icon);
card = (CardView) view.findViewById(R.id.card_view);
}
}
}
Вот простой и понятный способ добавить внутри вашего ReacyclerView
ViewHolder
public static class MyViewholder extends RecyclerView.ViewHolder {
public MyViewholder(View itemView) {
super(itemView);
itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("Tag", "onClick:" + getAdapterPosition());
}
});
}
}
getAdapterPosition()
возвращает текущую позицию выбранного элемента
Не изобретайте велосипед! Код для этого конкретного варианта использования включен в стартовый проект Master/Detail Flow, который поставляется с Android Studio.
В Android Studio выберите:
- Файл > New > New Project....
- На вкладке " Телефон и планшет " выберите, Master/Detail Flow как показано ниже.
- Создайте проект как Kotlin или Java.
- Прибыль.
Я не собираюсь включать код из демонстрационного проекта, но я опишу основные подходы к дизайну в образце, предоставленном Google:
- элемент OnClickListener создается ТОЛЬКО ОДИН РАЗ и назначается как поле в вашем
RecyclerView.Adapter
реализация. - в
onBindViewHolder()
затем вы устанавливаете тот же предварительно созданный onClickListener в своем экземпляре ViewHolder с помощьюholder.itemView.setOnClickListener(mOnClickListener)
(НЕ создавайте новый экземпляр при каждом вызове метода!); если вам нужно фиксировать клики по некоторым конкретным элементам внутри ViewHolder, расширьте ViewHolder и выставьте нужные вам элементы в виде полей, чтобы вы могли прикрепить любые нужные вам слушатели вonBindViewHolder()
- и еще раз, НЕ создавайте слушателей внутри метода - инициализируйте их как поля экземпляра и присоединяйте их по мере необходимости. - вы можете использовать
.setTag()
чтобы передать состояние вашему viewHolder, напримерholder.itemView.setTag(mValues.get(position));
как используется в демонстрации.
вот полный код для моего пользовательского адаптера, этот код будет раздувать строки с элементами списка, определенными в файле XML с именем "list_item", он также будет выполнять событие click для всех строк элементов списка с соответствующими позициями.
открытый класс MyCustomAdapter расширяет RecyclerView.Adapter<
AdapterMyCustomAdapter.ViewHolder> {
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener{
public onItemClickListener mListener;
public ViewHolder(View v, onItemClickListener listener) {
super(v);
mListener =listener;
v.setOnClickListener(this);
}
@Override
public void onClick(View v) {
mListener.onRecyclerItemClick(v, getPosition());
}
public static interface onItemClickListener {
public void onRecyclerItemClick(View view , int position);
}
}
@Override
public int getItemCount() {
return 5;
}
@Override
public void onBindViewHolder(ViewHolder holder, int pos) {
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
/* here list_item is an xml file we want to inflate ...it is same as we do in case of listview for customization.*/
MyCustomAdapter.ViewHolder vh = new ViewHolder(v, new MyCustomAdapter.ViewHolder.onItemClickListener() {
@Override
public void onRecyclerItemClick(View view, int position) {
System.out.println("clicked on list item at position " +position);
}
});
return vh;
}
}
public class MyViewHolder extends RecyclerView.ViewHolder {
public TextView title, year, genre;
public MyViewHolder(View view) {
super(view);
title = (TextView) view.findViewById(R.id.title);
genre = (TextView) view.findViewById(R.id.genre);
year = (TextView) view.findViewById(R.id.year);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(context, ""+getAdapterPosition(), Toast.LENGTH_SHORT).show();
}
});
}
}
Мы можем сделать это, используя слабые ссылки Java. Семантически держатель представления - это тот, кто должен ответить на событие щелчка или делегировать его правильному респонденту.
Наши цели:
- Viewholder не должен ничего знать о классе, отвечающем на события, за исключением того, что он реализует определенный интерфейс.
- Обработчик щелчка должен получить позицию в представлении Recycler для представления, по которому щелкнули.
- Мы должны быть в состоянии различить, какой вид был нажат в держателе вида.
- Поддерживайте слабую связь между всеми компонентами и не вызывайте циклов удержания.
шаги:
Создайте интерфейс для обработки ответов кликов.
Реализуйте этот интерфейс в Activity, которая будет обрабатывать щелчок.
Добавьте переменную-член в Адаптер RecyclerView для хранения Слабой ссылки и конструктор, который ее устанавливает.
Сделайте то же самое в RecyclerView ViewHolder и добавьте переменную-член, чтобы отслеживать положение.
Установите слушателей по щелчку на любом представлении, которое вы хотите в ViewHolder, а затем перезвоните респонденту, чтобы обработать их.
Измените метод onBindViewHolder, чтобы установить позицию при связывании.
Передайте ответчик вниз ViewHolder.
В респонденте теперь вы можете использовать getId() в представлении, чтобы выяснить, какое представление было нажато.
А вот Gist, чтобы вы могли увидеть, как все это сочетается: RecyclerView обработка кликов