6

RecyclerView onClick: Как обработать клики на элементах списка?

4

Подскажите, пожалуйста, нашел ли кто-нибудь способ установить onClickListener для элементов в RecyclerView? Я думал о том, чтобы назначить слушателя для каждого элемента в списке, но это кажется слишком сложным и трудоемким. Я уверен, что есть способ, чтобы RecyclerView обрабатывал события onClick, но я никак не могу разобраться с этой задачей.

5 ответ(ов)

6

Вот более удобный и менее связанно реализованный способ добавить обработчик кликов 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) {
            // выполнить нужное действие
        }

        @Override public void onLongItemClick(View view, int position) {
            // выполнить нужное действие
        }
    })
);

Реализация 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 {
        void onItemClick(View view, int position);
        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) {}
}

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

5

С учетом того, что 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();
}

Таким образом, вы сможете обрабатывать нажатия на каждый элемент списка.

1

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

Вот код адаптера:

public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> {
    private final ClickListener clickListener;

    public PasswordAdapter(ClickListener clickListener) {
         this.clickListener = clickListener;
    }

    public 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) {
            int position = getBindingAdapterPosition();
            if (position >= 0) {
                clickListener.onItemClick(position, v);
            }
        }

        @Override
        public boolean onLongClick(View v) {
            int position = getBindingAdapterPosition();
            if (position >= 0) { 
                clickListener.onItemLongClick(position, v);
                return true;
            }
            return false;
        }
    }

    public interface ClickListener {
        void onItemClick(int position, View v);
        void onItemLongClick(int position, View v);
    }
}

Затем внутри фрагмента или активности просто используйте:

PasswordAdapter mAdapter = new PasswordAdapter(
    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);
        }
    }
);

Таким образом, вы получаете простой и понятный способ обработки кликов и длинных нажатий без лишних усложнений.

0

В ответ на ваш вопрос, основываясь на ответе Джейкоба Табака (+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) {
        // Обработка долгого нажатия на элемент
    }
}));

Эта реализация позволит вам легко обрабатывать как клики, так и долгие нажатия на элементы вашего RecyclerView.

0

Вот что сработало для меня. Привязал OnClickListener в методе onBindViewHolder. Не уверен, повлияет ли это на производительность, но, похоже, всё работает нормально и требуется совсем немного кода.

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();
        }
    });
}
Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь