Tworzenie list dynamicznych za pomocą RecyclerView   Część Android Jetpack.

Wypróbuj tworzenie wiadomości
Jetpack Compose to zalecany zestaw narzędzi interfejsu na Androida. Dowiedz się, jak pracować z układami w Compose.

RecyclerView ułatwia wyświetlanie dużych zbiorów danych. Ty dostarczasz dane i określasz wygląd każdego elementu, a biblioteka RecyclerView dynamicznie tworzy elementy, gdy są potrzebne.

Jak sama nazwa wskazuje, RecyclerView przetwarza te poszczególne elementy. Gdy element zniknie z ekranu, RecyclerView nie zniszczy jego widoku. Zamiast tego RecyclerView ponownie używa widoku dla nowych elementów, które zostały przewinięte na ekranie. RecyclerView zwiększa wydajność i szybkość reakcji aplikacji oraz zmniejsza zużycie energii.

Kluczowe klasy

Lista dynamiczna jest tworzona przez kilka klas.

  • RecyclerView to ViewGroup, który zawiera widoki odpowiadające Twoim danym. Jest to widok, więc możesz dodać RecyclerViewdo układu w taki sam sposób, w jaki dodajesz inne elementy interfejsu.

  • Każdy element na liście jest zdefiniowany przez obiekt holder widoku. Gdy tworzysz widok, nie jest z nim powiązanych żadnych danych. Po utworzeniu RecyclerView wiąże go z danymi. Widok uchwytu definiujesz, rozszerzając element RecyclerView.ViewHolder.

  • RecyclerView wysyła żądania widoków i wiąże je z ich danymi, wywołując metody w adapterze. Definiujesz go, rozszerzając RecyclerView.Adapter.

  • Menedżer układu rozmieszcza poszczególne elementy na liście. Możesz użyć jednego z menedżerów układu udostępnianych przez bibliotekę RecyclerView lub zdefiniować własnego. Menedżerowie układów są oparte na abstrakcyjnej klasie LayoutManager biblioteki.

Sposób działania wszystkich elementów możesz sprawdzić w próbnej aplikacji RecyclerView (Kotlin) lub próbnej aplikacji RecyclerView (Java).

Wdrażanie RecyclerView

Jeśli chcesz użyć RecyclerView, musisz wykonać kilka czynności. Zostały one szczegółowo opisane w następnych sekcjach.

  1. Określ wygląd listy lub siatki. Zazwyczaj możesz użyć jednego ze standardowych menedżerów układu biblioteki RecyclerView.

  2. Zaprojektuj wygląd i działanie każdego elementu na liście. Na podstawie tego projektu rozszerz klasę ViewHolder. Twoja wersja ViewHolder zawiera wszystkie funkcje dotyczące elementów listy. Twój widok uchwytu to opakowanie View, a tym widokiem zarządza RecyclerView.

  3. Zdefiniuj Adapter, który łączy Twoje dane z widokami ViewHolder.

Dostępne są też zaawansowane opcje dostosowywania, które umożliwiają dostosowanie RecyclerView do Twoich potrzeb.

Planowanie układu

Elementy w RecyclerView są uporządkowane według klasy LayoutManager. Biblioteka RecyclerView udostępnia 3 menedżerów układu, które obsługują większość typowych sytuacji związanych z układem:

  • LinearLayoutManager umieszcza elementy na liście jednowymiarowej.
  • GridLayoutManager umieszcza elementy w dwudwumiarowej siatce:
    • Jeśli siatka jest ułożona w poziomie, GridLayoutManager stara się, aby wszystkie elementy w każdym wierszu miały taką samą szerokość i wysokość, ale różne wiersze mogą mieć różne wysokości.
    • Jeśli siatka jest ułożona poziomo, GridLayoutManager stara się, aby wszystkie elementy w każdej kolumnie miały taką samą szerokość i wysokość, ale różne kolumny mogą mieć różne szerokości.
  • StaggeredGridLayoutManager jest podobny do GridLayoutManager, ale nie wymaga, aby elementy w wierszu miały tę samą wysokość (w przypadku siatek pionowych) lub aby elementy w tej samej kolumnie miały tę samą szerokość (w przypadku siatek poziomych). W efekcie elementy w wierszu lub kolumnie mogą być przesunięte względem siebie.

Musisz też zaprojektować układ poszczególnych elementów. Ten układ jest potrzebny podczas projektowania widoku zasobnika, jak opisano w następnej sekcji.

Wdrażanie adaptera i uchwytu

Po ustaleniu układu musisz zaimplementować AdapterViewHolder. Te 2 klasy współpracują ze sobą, aby określić sposób wyświetlania danych. ViewHolder to element opakowujący View, który zawiera układ pojedynczego elementu na liście. W razie potrzeby usługa Adapter tworzy obiekty ViewHolder, a także ustawia dane dla tych widoków. Proces kojarzenia widoków z ich danymi nazywa się wiązaniem.

Podczas definiowania adaptera zastępujesz 3 kluczowe metody:

  • onCreateViewHolder(): RecyclerView wywołuje tę metodę, gdy musi utworzyć nowy obiekt ViewHolder. Metoda tworzy i inicjalizuje tabelę ViewHolder oraz powiązaną z nią tabelę View, ale nie wypełnia zawartości widoku – tabela ViewHolder nie została jeszcze powiązana z konkretnymi danymi.

  • onBindViewHolder(): RecyclerView wywołuje tę metodę, aby powiązać ViewHolder z danymi. Metoda pobiera odpowiednie dane i wypełnia nimi układ widoku. Jeśli na przykład RecyclerView wyświetla listę nazw, metoda może znaleźć odpowiednią nazwę na liście i wypełnić widget TextView widoczny dla właściciela.

  • getItemCount(): RecyclerView wywołuje tę metodę, aby uzyskać rozmiar zbioru danych. Na przykład w aplikacji książki adresowej może to być łączna liczba adresów. RecyclerView używa tego, aby określić, kiedy nie ma już żadnych elementów do wyświetlenia.

Oto typowy przykład prostego adaptera z zagnieżdżonym elementem ViewHolder, który wyświetla listę danych. W tym przypadku RecyclerView wyświetla prostą listę elementów tekstowych. Do adaptera przekazywana jest tablica ciągów znaków zawierająca tekst elementów ViewHolder.

Kotlin

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

}

Java

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;
    }
}

Układ każdego elementu widoku jest definiowany w pliku układu XML, jak zwykle. W tym przypadku aplikacja ma plik text_row_item.xml o takiej treści:

<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>

Dalsze kroki

Ten fragment kodu pokazuje, jak używać funkcji RecyclerView.

Kotlin

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

    }

}

Java

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

Biblioteka oferuje też wiele sposobów dostosowywania implementacji. Więcej informacji znajdziesz w artykule Zaawansowana personalizacja RecyclerView.

Dodatkowe materiały

Więcej informacji o testowaniu na Androidzie znajdziesz w tych materiałach.

Przykładowe aplikacje