Страницы

Поиск по вопросам

пятница, 27 декабря 2019 г.

Как добавить обработчик нажатия на элемент в RecyclerView?

#java #android #recyclerview


Мне нужен горизонтальный лист вью. Стал рыть в интернете, и нашел совет юзать RecyclerView.
Вроде это новая штука от гугл и тд. Вобщем вставил я его себе в проект. Выводит он
все нормально. Написал адаптер и тд. Но как теперь написать обработчик нажатия на айтем???
нашел реализацию этого всего вот тут RecyclerView onClick

Но в итоге получаю такое:

mRecyclerView.addOnItemTouchListener(
                new RecyclerItemClickListener(this, new RecyclerItemClickListener.OnItemClickListener() {
                    @Override public void onItemClick(View view, int position) {
                        Toast.makeText(DashboardActivity.this, "dfsdg"+ position,
Toast.LENGTH_LONG ).show();
                    }
                })
        );


как мне вместо "dfsdg"+ position вывести элемент моего списка??? гугл в очередной
раз меня огорчил.

ДОПОЛНИЛ

я добавил метод в адаптер:

public User getItem(int position){
    return userList.get(position);
}


теперь я имею возможность из вне вытащить свой айтем:

@Override
public void onItemClick(View view, int position) {
    Toast.makeText(DashboardActivity.this, ((RecyclerAdapter)mAdapter).getItem(position).getUserInfo().getName(),
Toast.LENGTH_LONG ).show();
}


Но мне не нравиться то, что я вынужден передавать mAdapter. В старом обычном листе
можно было обратиться к адаптеру из листвью. Тут этого нет, и как это сделать я не знаю. 

Как-то так:

public void onItemClick(AdapterView adapterView, View view, int i, long l) {
    adapterView.getAdapter().getItem(i)......
}


adapterView, а не передавать свой адаптер.
    


Ответы

Ответ 1



Для начала, почему же google не реализовала интерфейс onItemClickListener в своем новом виджете RecyclerView. Объясняется это тем, что данный интерфейс был весьма не совершенен и, в частности, создавал определенные трудности для обработки кликов на вложенных элементах айтема, также были определенные проблемы с получением реальной позиции и некоторые другие. Чтобы избавить себя от подобных проблем google решила доверить реализацию этого сомнительного действия самому программисту ... что же, какие у нас есть варианты. В первую очередь нужно понять, какого экшена мы чаще всего ожидаем от клика по элементу списка? Как правило это переход к другой активити со значением кликнутой позиции (каких то связанных с этой позицией данных адаптера и тп). Реализовать такое простое действие можно просто повешав слушатель прямо в адаптере. Здесь у нас есть доступ к текущей позиции и всем данным адаптера: @Override public void onBindViewHolder( ItemHolder holder, int position) { holder.someView.setOnClickListener (new View.OnClickListener() { @Override public void onClick(View v) { // action on click } }); } Однако IP696 в своем комментарии был прав, вешать сложную логику (если такая вдруг потребовалась для обработки клика по айтему) в адаптер не разумно. Следующий вариант - положить на доводы google и реализовать интерфейс onItemClicklListener() самостоятельно. При такой реализации мы можем передать "на сторону" через интерфейс множество полезных вещей: позицию, данные адаптера по кликнутому айтему, view айтема и тд. , но лишаем себя удобной возможности простым способом обрабатывать клики на дочерних элементах, как это можно было сделать в первом варианте и о чем предупреждал нас google. Кроме того, фактически, как правило, нет никакой прямой необходимости обрабатывать клик по айтему на "внешней" стороне. Пример: public class ListAdapterHolder extends RecyclerView.Adapter { OnItemClickListener mItemClickListener; @Override public ViewHolder onCreateViewHolder(ViewGroup parent , int viewType) { ... return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder , int position) { ... } public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public ViewHolder(View view) { super(view); view.setOnClickListener(this); ... //здесь можно повесить слушатель и на отдельные виджеты в айтеме } @Override public void onClick(View v) { if (mItemClickListener != null) { mItemClickListener.onItemClick(v, getAdapterPosition()); } } } public interface OnItemClickListener { public void onItemClick(View view , int position); } public void SetOnItemClickListener(final OnItemClickListener mItemClickListener) { this.mItemClickListener = mItemClickListener; } } Наиболее логичным решением ситуации я считаю решение обрабатывать клики в классе-холдере адаптера. Здесь у нас есть простой и прямой доступ ко всем элементам айтема, данные самого адаптера (так как класс вложен в адаптер) для простого добавления\изменения\удаления пунктов списка, кроме того через конструктор можно передать дополнительные данные, кроме, собственно View, также логика обработки кликов выведена из адаптера в статический холдер: public static class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener { TextView mText; Button mButton; CardView mCard; public ItemHolder(View v) { super(v); mCard = (CardView) v.findViewById(R.id.item_card); mText = (TextView) v.findViewById(R.id.item_text); mButton = (Button) v.findViewById(R.id.item_button); mCard.setOnClickListener(this); mButton.setOnClickListener(this); } @Override public void onClick(View v) { int position = getAdapterPosition(); if (position != RecyclerView.NO_POSITION) { switch (v.getId()) { case R.id.card: itemClick(position); break; case R.id.button: buttonClick(position); } } } private void itemClick(int position){ //action on item click } private void buttonClick (int position){ //action on button click } } Так же, если клик нужно обработать в активити, то можно просто указать в xml-разметке айтема списка метод обработки клика (android:onClick) и реализовать его в активити. Подробнее

Ответ 2



Ответ @pavlofff верен. Единственный вопрос где обработать нажатие. В своем проекте мы используем для этого шину событий (Otto by Square). Что то вроде: public class Adapter extends RecyclerView.Adapter { @Inject Bus bus; @Override public void onBindViewHolder( ItemHolder holder, final int position) { holder.view.setOnClickListener (new View.OnClickListener() { @Override public void onClick(View v) { bus.post(new ItemClickedEvent(getItem(position))); } }); } } В нужном месте ловим ItemClickedEvent, который содержит в себе модель, ячейка с которой была выбрана. Странно, конечно, что Google не добавила callback как для listview.

Комментариев нет:

Отправить комментарий