Создавайте динамические списки с помощью RecyclerView, входящего в состав Android Jetpack .

Попробуйте способ создания
Jetpack Compose — рекомендуемый набор инструментов пользовательского интерфейса для Android. Узнайте, как работать с макетами в Compose.

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

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

Ключевые классы

Несколько классов работают вместе для создания динамического списка.

  • RecyclerView — это ViewGroup , содержащий представления, соответствующие вашим данным. Это само по себе представление, поэтому вы добавляете RecyclerView в свой макет так же, как любой другой элемент пользовательского интерфейса.

  • Каждый отдельный элемент в списке определяется объектом- держателем представления . Когда держатель представления создан, с ним не связаны никакие данные. После создания держателя представления RecyclerView привязывает его к своим данным. Вы определяете держателя представления, расширяя RecyclerView.ViewHolder .

  • RecyclerView запрашивает представления и привязывает представления к их данным, вызывая методы в адаптере. Вы определяете адаптер, расширяя RecyclerView.Adapter .

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

Вы можете увидеть, как все части сочетаются друг с другом, в примере приложения RecyclerView (Kotlin) или примере приложения RecyclerView (Java) .

Шаги по реализации вашего RecyclerView

Если вы собираетесь использовать RecyclerView, вам нужно сделать несколько вещей. Они подробно описаны в следующих разделах.

  1. Решите, как будет выглядеть список или сетка. Обычно вы можете использовать один из стандартных менеджеров макетов библиотеки RecyclerView.

  2. Спроектируйте, как будет выглядеть и вести себя каждый элемент в списке. На основе этого проекта расширьте класс ViewHolder . Ваша версия ViewHolder предоставляет все функции для элементов вашего списка. Держатель представления — это оболочка View , и этим представлением управляет RecyclerView .

  3. Определите Adapter , который связывает ваши данные с представлениями ViewHolder .

Существуют также расширенные параметры настройки , которые позволяют адаптировать RecyclerView под ваши нужды.

Спланируйте свою планировку

Элементы в вашем RecyclerView упорядочены классом LayoutManager . Библиотека RecyclerView предоставляет три менеджера компоновки, которые обрабатывают наиболее распространенные ситуации компоновки:

  • LinearLayoutManager упорядочивает элементы в одномерный список.
  • GridLayoutManager упорядочивает элементы в двумерной сетке:
    • Если сетка расположена вертикально, GridLayoutManager пытается сделать так, чтобы все элементы в каждой строке имели одинаковую ширину и высоту, но разные строки могут иметь разную высоту.
    • Если сетка расположена горизонтально, GridLayoutManager пытается сделать так, чтобы все элементы в каждом столбце имели одинаковую ширину и высоту, но разные столбцы могут иметь разную ширину.
  • StaggeredGridLayoutManager похож на GridLayoutManager , но не требует, чтобы элементы в строке имели одинаковую высоту (для вертикальных сеток) или элементы в одном столбце имели одинаковую ширину (для горизонтальных сеток). В результате элементы в строке или столбце могут оказаться смещенными друг от друга.

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

Реализуйте свой адаптер и держатель представления

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

Когда вы определяете свой адаптер, вы переопределяете три ключевых метода:

  • onCreateViewHolder() : RecyclerView вызывает этот метод всякий раз, когда ему необходимо создать новый ViewHolder . Метод создает и инициализирует ViewHolder и связанный с ним View , но не заполняет содержимое представления — ViewHolder еще не привязан к конкретным данным.

  • onBindViewHolder() : RecyclerView вызывает этот метод, чтобы связать ViewHolder с данными. Метод извлекает соответствующие данные и использует их для заполнения макета держателя представления. Например, если RecyclerView отображает список имен, метод может найти подходящее имя в списке и заполнить виджет TextView держателя представления.

  • getItemCount() : RecyclerView вызывает этот метод, чтобы получить размер набора данных. Например, в приложении адресной книги это может быть общее количество адресов. RecyclerView использует это, чтобы определить, когда больше нет элементов, которые можно отобразить.

Вот типичный пример простого адаптера с вложенным ViewHolder , отображающим список данных. В этом случае RecyclerView отображает простой список текстовых элементов. Адаптеру передается массив строк, содержащий текст для элементов ViewHolder .

Котлин

class CustomAdapter(private val dataSet: Array<String>) :
        RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

    /**
     * Provide a reference to the type of views that you are using
     * (custom ViewHolder)
     */
    class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val textView: TextView

        init {
            // Define click listener for the ViewHolder's View
            textView = view.findViewById(R.id.textView)
        }
    }

    // Create new views (invoked by the layout manager)
    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        // Create a new view, which defines the UI of the list item
        val view = LayoutInflater.from(viewGroup.context)
                .inflate(R.layout.text_row_item, viewGroup, false)

        return ViewHolder(view)
    }

    // Replace the contents of a view (invoked by the layout manager)
    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {

        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.textView.text = dataSet[position]
    }

    // Return the size of your dataset (invoked by the layout manager)
    override fun getItemCount() = dataSet.size

}

Ява

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {

    private String[] localDataSet;

    /**
     * Provide a reference to the type of views that you are using
     * (custom ViewHolder)
     */
    public static class ViewHolder extends RecyclerView.ViewHolder {
        private final TextView textView;

        public ViewHolder(View view) {
            super(view);
            // Define click listener for the ViewHolder's View

            textView = (TextView) view.findViewById(R.id.textView);
        }

        public TextView getTextView() {
            return textView;
        }
    }

    /**
     * Initialize the dataset of the Adapter
     *
     * @param dataSet String[] containing the data to populate views to be used
     * by RecyclerView
     */
    public CustomAdapter(String[] dataSet) {
        localDataSet = dataSet;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        // Create a new view, which defines the UI of the list item
        View view = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.text_row_item, viewGroup, false);

        return new ViewHolder(view);
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {

        // Get element from your dataset at this position and replace the
        // contents of the view with that element
        viewHolder.getTextView().setText(localDataSet[position]);
    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return localDataSet.length;
    }
}

Макет каждого элемента представления, как обычно, определяется в файле макета XML. В этом случае в приложении есть такой файл text_row_item.xml :

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/list_item_height"
    android:layout_marginLeft="@dimen/margin_medium"
    android:layout_marginRight="@dimen/margin_medium"
    android:gravity="center_vertical">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/element_text"/>
</FrameLayout>

Следующие шаги

В следующем фрагменте кода показано, как можно использовать RecyclerView .

Котлин

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val dataset = arrayOf("January", "February", "March")
        val customAdapter = CustomAdapter(dataset)

        val recyclerView: RecyclerView = findViewById(R.id.recycler_view)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = customAdapter

    }

}

Ява

RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.layoutManager = new LinearLayoutManager(this)
recyclerView.setAdapter(customAdapter);

Библиотека также предлагает множество способов настройки вашей реализации. Дополнительные сведения см. в разделе Расширенная настройка RecyclerView .

Дополнительные ресурсы

Для получения дополнительной информации о тестировании на Android обратитесь к следующим ресурсам.

Примеры приложений