Tworzenie dynamicznych list za pomocą widoku RecyclerView, części Androida Jetpack.
RecyclerView ułatwia wydajne wyświetlanie dużych zbiorów danych. Dostarczasz dane i określasz wygląd poszczególnych elementów, a biblioteka RecyclerView dynamicznie tworzy elementy, gdy są potrzebne.
Zgodnie z nazwą RecyclerView ponownie wykorzystuje te poszczególne elementy. Gdy element zniknie z ekranu, RecyclerView nie niszczy jego widoku. Zamiast tego widok RecyclerView ponownie wykorzystuje widok dla nowych elementów, które zostały przewinięte na ekran. RecyclerView zwiększa wydajność i szybkość reakcji aplikacji oraz zmniejsza zużycie energii.
Kluczowe klasy
Kilka klas współpracuje ze sobą, aby utworzyć dynamiczną listę.
- RecyclerViewto- ViewGroup, która zawiera widoki odpowiadające Twoim danym. Jest to widok, więc dodajesz go do układu w taki sam sposób jak każdy inny element interfejsu.- RecyclerView
- Każdy element na liście jest zdefiniowany przez obiekt uchwytu widoku. Gdy tworzony jest uchwyt widoku, nie są z nim powiązane żadne dane. Po utworzeniu obiektu widoku - RecyclerViewwiąże go z danymi. Uchwyt widoku definiujesz, rozszerzając klasę- RecyclerView.ViewHolder.
- RecyclerViewwysyła żądania dotyczące widoków i wiąże je z danymi, wywołując metody w adapterze. Adapter definiujesz, rozszerzając klasę- 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łasny. Wszyscy menedżerowie układu są oparci na klasie abstrakcyjnej biblioteki - LayoutManager.
Możesz zobaczyć, jak wszystkie elementy pasują do siebie, w przykładowej aplikacji RecyclerView (Kotlin) lub przykładowej aplikacji RecyclerView (Java).
Instrukcje wdrażania elementu RecyclerView
Jeśli zamierzasz używać elementu RecyclerView, musisz wykonać kilka czynności. Szczegółowe informacje znajdziesz w sekcjach poniżej.
- Zdecyduj, jak ma wyglądać lista lub siatka. Zwykle możesz użyć jednego ze standardowych menedżerów układu biblioteki RecyclerView. 
- Zaprojektuj wygląd i działanie każdego elementu na liście. Na podstawie tego projektu rozszerz klasę - ViewHolder. Twoja wersja- ViewHolderzapewnia wszystkie funkcje elementów listy. Element View Holder jest otoczką elementu- View, a tym widokiem zarządza- RecyclerView.
- Określ parametr - Adapter, który powiąże Twoje dane z widokami- ViewHolder.
Dostępne są też zaawansowane opcje dostosowywania, które pozwalają dopasować element RecyclerView do Twoich konkretnych potrzeb.
Planowanie układu
Elementy w obiekcie RecyclerView są rozmieszczone według klasy 
LayoutManager. Biblioteka RecyclerView udostępnia 3 menedżerów układu, którzy obsługują najczęstsze sytuacje związane z układem:
- LinearLayoutManagerrozmieszcza elementy na liście jednowymiarowej.
- GridLayoutManagerukłada elementy w dwuwymiarowej siatce:- Jeśli siatka jest ułożona pionowo, GridLayoutManagerstara się, aby wszystkie elementy w każdym wierszu miały taką samą szerokość i wysokość, ale różne wiersze mogą mieć różną wysokość.
- Jeśli siatka jest ułożona poziomo, GridLayoutManagerpróbuje ustawić wszystkie elementy w każdej kolumnie tak, aby miały tę samą szerokość i wysokość, ale różne kolumny mogą mieć różną szerokość.
 
- Jeśli siatka jest ułożona pionowo, 
- StaggeredGridLayoutManagerdziała podobnie jak- GridLayoutManager, ale nie wymaga, aby elementy w wierszu miały tę samą wysokość (w przypadku siatek pionowych) ani aby elementy w tej samej kolumnie miały tę samą szerokość (w przypadku siatek poziomych). W rezultacie 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, zgodnie z opisem w następnej sekcji.
Wdrażanie adaptera i wyświetlanie modułu
Po określeniu układu musisz wdrożyć Adapter i ViewHolder. Te 2 klasy współpracują ze sobą, aby określić sposób wyświetlania danych. Element ViewHolder jest otoczką elementu View, który zawiera układ pojedynczego elementu na liście. Usługa Adapter tworzy w razie potrzeby obiekty ViewHolder
i ustawia dla nich dane. Proces przypisywania widoków do danych nazywa się wiązaniem.
Definiując adapter, zastępujesz 3 kluczowe metody:
- onCreateViewHolder():- RecyclerViewwywołuje tę metodę za każdym razem, gdy musi utworzyć nowy- ViewHolder. Metoda tworzy i inicjuje obiekt- ViewHolderoraz powiązany z nim obiekt- View, ale nie wypełnia zawartości widoku – obiekt- ViewHoldernie został jeszcze powiązany z konkretnymi danymi.
- onBindViewHolder():- RecyclerViewwywołuje tę metodę, aby powiązać- ViewHolderz danymi. Metoda pobiera odpowiednie dane i używa ich do wypełnienia układu obiektu View Holder. Jeśli na przykład- RecyclerViewwyświetla listę nazw, metoda może znaleźć odpowiednią nazwę na liście i wypełnić widżet- TextVieww uchwycie widoku.
- getItemCount():- RecyclerViewwywoł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ż więcej elementów, które można wyświetlić.
Oto typowy przykład prostego adaptera z zagnieżdżonym elementem ViewHolder, który wyświetla listę danych. W tym przypadku element RecyclerView wyświetla prostą listę elementów tekstowych. Do adaptera przekazywana jest tablica ciągów tekstowych zawierających 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 zdefiniowany w pliku układu XML, tak jak zwykle.
W tym przypadku aplikacja ma plik text_row_item.xml o takiej zawartoś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
Poniższy fragment kodu pokazuje, jak używać znaku 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 Zaawansowane dostosowywanie elementu RecyclerView.
Włącz wyświetlanie bez ramki
Aby włączyć wyświetlanie bez ramki na urządzeniu RecyclerView:
- Aby skonfigurować wyświetlanie bez ramki zgodne wstecznie, wywołaj funkcję
enableEdgeToEdge().
- Jeśli elementy listy początkowo nakładają się na paski systemowe, zastosuj wcięcia w RecyclerView. Możesz to zrobić, ustawiającandroid:fitsSystemWindowsnatruelub używającViewCompat.setOnApplyWindowInsetsListener.
- Aby umożliwić rysowanie elementów listy pod paskami systemowymi podczas przewijania, ustaw wartość android:clipToPaddingnafalsewRecyclerView.
Poniższy film pokazuje RecyclerView z wyłączonym (po lewej) i włączonym (po prawej) wyświetlaczem od krawędzi do krawędzi:
Przykładowy kod wstawki:
Kotlin
ViewCompat.setOnApplyWindowInsetsListener( findViewById(R.id.my_recycler_view) ) { v, insets -> val innerPadding = insets.getInsets( WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.displayCutout() // If using EditText, also add // "or WindowInsetsCompat.Type.ime()" to // maintain focus when opening the IME ) v.setPadding( innerPadding.left, innerPadding.top, innerPadding.right, innerPadding.bottom) insets }
Java
ViewCompat.setOnApplyWindowInsetsListener( activity.findViewById(R.id.my_recycler_view), (v, insets) -> { Insets innerPadding = insets.getInsets( WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout() // If using EditText, also add // "| WindowInsetsCompat.Type.ime()" to // maintain focus when opening the IME ); v.setPadding( innerPadding.left, innerPadding.top, innerPadding.right, innerPadding.bottom ); return insets; } );
RecyclerView XML:
<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/my_recycler_view"
    android:clipToPadding="false"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
Dodatkowe materiały
Więcej informacji o testowaniu na Androidzie znajdziesz w tych materiałach.
 
  