Как отобразить ArrayList в RecyclerView?

Мне нужно добавить Activity, где я могу перечислять элементы ArrayList<CustomClass>, и я видел там более новый и лучший способ отображения списков - RecyclerView.

Мой вопрос заключается в том, как реализовать это в моем приложении. Я обнаружил, что мне нужно использовать Adapter, но я не совсем понимаю, как правильно реализовать весь процесс.

Если вам интересно, я имею в виду это примеры документов, которые я читал.

EDIT:

После обновления моего кода он говорит, что не может разрешить символ setOnEntryClickListener:

public class voting extends Activity {


RecyclerView myList;
private ArrayList<Player> players; // Players


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_voting);

    Intent intent = this.getIntent();
    Bundle bundle = intent.getExtras();
    players = (ArrayList<Player>)bundle.getSerializable("PLAYERS");

    myList = (RecyclerView) findViewById(R.id.charactersList);
    myList.setLayoutManager(new LinearLayoutManager(this));
    CoursesAdapter adapter = new CoursesAdapter(players);
    myList.setAdapter(adapter);
}

// OR RecyclerView with a click listener

CoursesAdapter clickAdapter = new CoursesAdapter(players);
clickAdapter.setOnEntryClickListener(new CoursesAdapter.OnEntryClickListener() {
    @Override
    public void onEntryClick(View view, int position) {
        // stuff that will happen when a list item is clicked
    }
});
recyclerView.setAdapter(clickAdapter);
}

Итак, я думал, что поставил interface в неправильное место (возможно, очень)), infact Я поместил его в класс адаптера в конце его сразу после метода onAttachedToRecyclerView():

    @Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
}


private OnEntryClickListener mOnEntryClickListener;

public interface OnEntryClickListener {
    void onEntryClick(View view, int position);
}

public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) {
    mOnEntryClickListener = onEntryClickListener;
}



}

Ответ 1

Помню, когда я впервые прочитал о RecyclerView - я согласен, что это может быть немного запутанным вначале. Надеюсь, это объяснение поможет вам лучше понять.


Основы RecyclerView

1. Добавление RecyclerView

Сначала вам нужно добавить RecyclerView в свой XML-макет. Я предполагаю, что вы знаете, как это сделать. Вы также объявляете это в своем Java-коде:

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.your_recycler_view);

2. Создание Adapter и понимание ViewHolder

Затем вам нужно создать Adapter. Это класс, который реализует RecyclerView.Adapter<YourAdapter.YourViewHolder>. Я объясню, что это означает через минуту.

Я считаю, что это помогает взглянуть на пример Adapter, чтобы понять, как он работает (например, тот, который я создал для open- исходное приложение). Я также настоятельно рекомендую просмотреть набор файлов Java, которые я привел в качестве примера в Gist на GitHub:

https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07

Я буду ссылаться на файлы примеров из ссылки выше в этом объяснении, чтобы вы могли следовать.

Вы можете видеть, что класс Adapter содержит внутренний класс, который является вашим ViewHolder. Поэтому ему необходимо расширить RecyclerView.ViewHolder.

Внутри этого ViewHolder вы объявляете переменные для макетов, которые будут использоваться для каждого элемента списка в RecyclerView. В конструкторе для вашего ViewHolder вы назначаете эти переменные. Я имею в виду эту часть кода (я приводил свой пример ниже):

    ExampleViewHolder(View itemView) {
        super(itemView);
        text1 = (TextView) itemView.findViewById(R.id.text1);
        text2 = (TextView) itemView.findViewById(R.id.text2);
    }

Это все, что вам нужно для вашего ViewHolder (внутренний класс в вашем Adapter).

3. Понимание Adapter

Как и большинство объектов Java, вам нужно будет иметь конструктор некоторых частных переменных в вашем классе Adapter. Вот мои:

private ArrayList<CustomClass> mCustomObjects;

public ExampleAdapter(ArrayList<CustomClass> arrayList) {
    mCustomObjects = arrayList;
}

Вам нужно будет указать ArrayList<CustomClass> как конструктор, чтобы вы могли передать список, чтобы ваш Adapter мог его использовать.

Если вы посмотрите на остальную часть класса Adapter, он содержит некоторые методы, которые он переопределяет от того, что он расширяет. Давайте быстро посмотрим, что это такое:

  • getItemCount() возвращает размер вашего списка.
  • onCreateViewHolder(...) используется для раздувания макета для вашего элемента списка.
  • onBindViewHolder(...) настраивает ваши макеты для элемента списка (например, установка текста в TextView)

В большинстве случаев getItemCount() просто вернет size() вашего ArrayList<CustomClass>.

Метод onCreateViewHolder(...) обычно остается таким же:

@Override
public ExampleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_2, parent, false);
    return new ExampleViewHolder(view);
}

Вы можете видеть, что я раздуваю макет, который я буду использовать в качестве элемента списка (android.R.layout.simple_list_item_2). Этот макет встроен в Android, поэтому мне не нужно его создавать - конечно, вы можете использовать любой макет, который хотите, а затем изменить свой Adapter для виджетов, которые вы можете использовать. Тип возврата этого метода будет соответствовать тому, что вы назвали своим внутренним классом ViewHolder.

Теперь интересный бит находится в onBindViewHolder(...). Здесь вы настраиваете свои макеты, поэтому полностью зависит от вас, что вы хотите сделать. Здесь вы можете использовать шаблон:

@Override
public void onBindViewHolder(ExampleViewHolder holder, int position) {
    CustomClass object = mCustomObjects.get(position);

    String firstText = object.getFirstText()
    String secondText = object.getSecondText()

    holder.text1.setText(firstText);
    holder.text2.setText(secondText);
}

В принципе, вы получаете доступ к своим переменным ViewHolder (для виджетов в макете вашего списка), делая holder.myWidget. Часть holder исходит из параметра, который является вашим ViewHolder, о котором мы говорили ранее, и myWidget будет именем переменной View.

В приведенном выше примере object имеет метод getFirstText(), а ViewHolder содержит TextView (text1), поэтому я устанавливаю текст.

Существует еще один метод - onAttachedToRecyclerView(...). Вы можете использовать это для более сложных вещей, но на базовом уровне обычно это:

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
}

4. Конфигурирование RecyclerView

Помните в начале, когда мы объявили и назначили наш RecyclerView?:

RecyclerView recyclerView = (RecyclerView) findViewById(R.id.your_recycler_view);

Теперь мы настроим его.

Вы начинаете с установки "менеджера макетов". Это определяет, как каждый элемент списка будет отображаться на экране. Обычными являются LinearLayoutManager и GridLayoutManager. Первый помещает элементы списка в стандартный список (ничего особенного, но очень полезно), а последний упорядочивает элементы списка в виде сетки.

В нашем примере мы будем использовать LinearLayoutManager. Чтобы установить это на RecyclerView, мы делаем следующее:

recyclerView.setLayoutManager(new LinearLayoutManager(this));

Что все.

И все, что нам нужно сделать, это установить класс Adapter, который мы создали и настроили ранее, на RecyclerView:

ExampleAdapter adapter = new ExampleAdapter(yourCustomArrayList);
recyclerView.setAdapter(adapter);

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

5. Используя RecyclerView

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

Вы также можете просмотреть образцы Google для реализации RecyclerView.

Я надеюсь, что все это дало вам четкое представление о том, как работает RecyclerView.


Добавление прослушивателя кликов

Вам может понадобиться добавить прослушиватель кликов, чтобы вы не использовали RecyclerView только для отображения элементов.

Для этого вашему внутреннему классу ViewHolder необходимо реализовать View.OnClickListener. Это связано с тем, что вы установите OnClickListener в параметр itemView конструктора ViewHolder. Позвольте мне показать вам, что я имею в виду:

public class ExampleClickViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    TextView text1, text2;

    ExampleClickViewHolder(View itemView) {
        super(itemView);

        // we do this because we want to check when an item has been clicked:
        itemView.setOnClickListener(this);

        // now, like before, we assign our View variables
        title = (TextView) itemView.findViewById(R.id.text1);
        subtitle = (TextView) itemView.findViewById(R.id.text2);
    }

    @Override
    public void onClick(View v) {
        // The user may not set a click listener for list items, in which case our listener
        // will be null, so we need to check for this
        if (mOnEntryClickListener != null) {
            mOnEntryClickListener.onEntryClick(v, getLayoutPosition());
        }
    }
}

Единственное, что вам нужно добавить, это настраиваемый интерфейс для вашего Adapter и метода сеттера:

private OnEntryClickListener mOnEntryClickListener;

public interface OnEntryClickListener {
    void onEntryClick(View view, int position);
}

public void setOnEntryClickListener(OnEntryClickListener onEntryClickListener) {
    mOnEntryClickListener = onEntryClickListener;
}

Итак, ваш новый, поддерживающий клики Adapter завершен.

Теперь, используйте его...

    ExampleClickAdapter clickAdapter = new ExampleClickAdapter(yourObjects);
    clickAdapter.setOnEntryClickListener(new ExampleClickAdapter.OnEntryClickListener() {
        @Override
        public void onEntryClick(View view, int position) {
            // stuff that will happen when a list item is clicked
        }
    });
    recyclerView.setAdapter(clickAdapter);

В основном, как вы настроите обычный Adapter, за исключением того, что вы используете свой метод setter, который вы создали, чтобы контролировать, что вы будете делать, когда пользователь нажимает на определенный элемент списка.


Чтобы повторить, вы можете просмотреть набор примеров, которые я сделал в этом Gist на GitHub:

https://gist.github.com/FarbodSalamat-Zadeh/7646564f48ee708c1582c013e1de4f07

Ответ 2

Вот рабочий пример, надеюсь, он вам поможет:

public class BankListAdapter extends RecyclerView.Adapter<BankListAdapter.BankListViewHolder> {

    ArrayList<BankListModel> bankListModels;
    FragmentActivity activity;
    View selectBank;

    public BankListAdapter(ArrayList<BankListModel> bankListModels, FragmentActivity activity) {
        this.bankListModels=bankListModels;
        this.activity=activity;
    }


    @Override
    public BankListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View bankListLayout = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bank_list, null);
        BankListViewHolder bankListViewHolder = new BankListViewHolder(bankListLayout);
        return bankListViewHolder;
    }

    @Override
    public void onBindViewHolder(BankListViewHolder holder, int position) {
        holder.bankName.setText(bankListModels.get(position).getBankName());

    }

    @Override
    public int getItemCount() {
        return bankListModels.size();
    }

    public class BankListViewHolder extends RecyclerView.ViewHolder {
        TextView bankName;

        public BankListViewHolder(View itemView) {
            super(itemView);
            bankName = (TextView) itemView.findViewById(R.id.tv_bankName);
            selectBank = itemView.findViewById(R.id.cv_selectBank);

        }
    }
}