יצירת רשימות דינמיות באמצעות RecyclerView בארגז הכלים Android Jetpack.
RecyclerView מאפשר להציג ביעילות קבוצות גדולות של נתונים. אתם מספקים את הנתונים ומגדירים איך כל פריט נראה, וספריית RecyclerView יוצרת את הרכיבים באופן דינמי כשצריך אותם.
כמו שהשם מרמז, RecyclerView ממחזר את הרכיבים הנפרדים האלה. כשפריט נגלל אל מחוץ למסך, RecyclerView לא משמיד את התצוגה שלו. במקום זאת, RecyclerView משתמש מחדש בתצוגה לפריטים חדשים שנגללו למסך. RecyclerView משפר את הביצועים ואת מהירות התגובה של האפליקציה, ומפחית את צריכת החשמל.
כיתות מפתח
כמה מחלקות פועלות יחד כדי ליצור את הרשימה הדינמית.
RecyclerViewהוא ה-ViewGroupשמכיל את התצוגות שמתאימות לנתונים שלכם. הוא בעצמו תצוגה, אז מוסיפים אתRecyclerViewלפריסה כמו שמוסיפים כל רכיב בממשק המשתמש.כל רכיב בודד ברשימה מוגדר על ידי אובייקט view holder. כשיוצרים את ה-view holder, לא משויכים אליו נתונים. אחרי שיוצרים את ה-view holder, ה-
RecyclerViewמקשר אותו לנתונים שלו. מגדירים את מחזיק התצוגה על ידי הרחבה שלRecyclerView.ViewHolder.ה-
RecyclerViewמבקש תצוגות וקושר אותן לנתונים שלהן באמצעות קריאה לשיטות במתאם. כדי להגדיר את המתאם, מרחיבים אתRecyclerView.Adapter.מנהל הפריסה מסדר את הרכיבים הנפרדים ברשימה. אתם יכולים להשתמש באחד ממנהלי הפריסה שספריית RecyclerView מספקת, או להגדיר מנהל פריסה משלכם. כל מנהלי הפריסות מבוססים על המחלקה המופשטת
LayoutManagerשל הספרייה.
אתם יכולים לראות איך כל החלקים משתלבים יחד באפליקציה לדוגמה של RecyclerView (Kotlin) או באפליקציה לדוגמה של RecyclerView (Java).
שלבים להטמעת RecyclerView
אם אתם מתכוונים להשתמש ב-RecyclerView, יש כמה דברים שאתם צריכים לעשות. הם מוסברים בפירוט בקטעים הבאים.
בוחרים איך הרשימה או הרשת ייראו. בדרך כלל, אפשר להשתמש באחד ממנהלי הפריסה הרגילים של ספריית RecyclerView.
מעצבים את המראה וההתנהגות של כל רכיב ברשימה. על סמך העיצוב הזה, הרחיבו את המחלקה
ViewHolder. הגרסה שלViewHolderמספקת את כל הפונקציונליות של הפריטים ברשימה. ה-view holder הוא wrapper סביבView, והתצוגה הזו מנוהלת על ידיRecyclerView.מגדירים את
Adapterשמשייך את הנתונים לתצוגות המפורטות שלViewHolder.
יש גם אפשרויות מתקדמות להתאמה אישית שמאפשרות להתאים את RecyclerView לצרכים הספציפיים שלכם.
תכנון הפריסה
הפריטים ב-RecyclerView מסודרים לפי מחלקה מסוג LayoutManager. ספריית RecyclerView מספקת שלושה מנהלי פריסה, שמטפלים במצבי הפריסה הנפוצים ביותר:
LinearLayoutManagerמסדר את הפריטים ברשימה חד-ממדית.GridLayoutManagerמסדר את הפריטים ברשת דו-ממדית:- אם הרשת מסודרת אנכית,
GridLayoutManagerמנסה להגדיר לכל הרכיבים בכל שורה את אותו רוחב ואותו גובה, אבל לשורות שונות יכולים להיות גבהים שונים. - אם הרשת מסודרת אופקית,
GridLayoutManagerמנסה להגדיר לכל הרכיבים בכל עמודה את אותו רוחב ואותו גובה, אבל לעמודות שונות יכולים להיות רוחבים שונים.
- אם הרשת מסודרת אנכית,
StaggeredGridLayoutManagerדומה ל-GridLayoutManager, אבל לא מחייב שלפריטים בשורה יהיה אותו גובה (ברשתות אנכיות) או שלפריטים באותה עמודה יהיה אותו רוחב (ברשתות אופקיות). כתוצאה מכך, הפריטים בשורה או בעמודה עלולים להיות מוסטים זה מזה.
צריך גם לעצב את הפריסה של הפריטים הנפרדים. תצטרכו את הפריסה הזו כשתעצבו את ה-ViewHolder, כפי שמתואר בקטע הבא.
הטמעת המתאם ומחזיק התצוגה
אחרי שבוחרים את הפריסה, צריך להטמיע את Adapter ו-ViewHolder. שתי המחלקות האלה פועלות יחד כדי להגדיר איך הנתונים יוצגו. ViewHolder הוא מעטפת של View שמכיל את הפריסה של פריט בודד ברשימה. ה-Adapter יוצר אובייקטים מסוג ViewHolder לפי הצורך, וגם מגדיר את הנתונים לתצוגות האלה. התהליך של שיוך תצוגות לנתונים שלהן נקרא קישור.
כשמגדירים את המתאם, מבטלים שלוש שיטות עיקריות:
onCreateViewHolder(): RecyclerViewקורא ל-method הזה בכל פעם שצריך ליצורViewHolderחדש. השיטה יוצרת ומאתחלת את ה-ViewHolderואת ה-Viewשמשויך אליו, אבל לא ממלאת את התוכן של התצוגה – ה-ViewHolderעדיין לא קושר לנתונים ספציפיים.
onBindViewHolder():RecyclerViewקורא ל-method הזה כדי לשייךViewHolderלנתונים. מאחזרת את הנתונים המתאימים ומשתמשת בהם כדי למלא את הפריסה של מחזיק התצוגה. לדוגמה, אםRecyclerViewמציג רשימת שמות, יכול להיות שה-method ימצא את השם המתאים ברשימה וימלא את הווידג'טTextViewשל ה-view holder.
getItemCount():RecyclerViewקורא ל-method הזה כדי לקבל את הגודל של מערך הנתונים. לדוגמה, באפליקציה של פנקס כתובות, זה יכול להיות המספר הכולל של הכתובות. RecyclerView משתמש בזה כדי לקבוע מתי אין יותר פריטים שאפשר להציג.
הנה דוגמה טיפוסית למתאם פשוט עם ViewHolder בתצוגה מקוננת שמציג רשימה של נתונים. במקרה הזה, ה-RecyclerView מציג רשימה פשוטה של רכיבי טקסט. המתאם מקבל מערך של מחרוזות שמכילות את הטקסט של רכיבי 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; } }
הפריסה של כל פריט תצוגה מוגדרת בקובץ פריסת 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.
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);
הספרייה גם מציעה דרכים רבות להתאים אישית את ההטמעה. מידע נוסף זמין במאמר התאמה אישית מתקדמת של RecyclerView.
הפעלת תצוגה מקצה לקצה
כדי להפעיל תצוגה מקצה לקצה ב-RecyclerView:
- כדי להגדיר תצוגה מקצה לקצה שתואמת לדור קודם, מפעילים את
enableEdgeToEdge(). - אם הפריטים ברשימה חופפים בהתחלה לסרגלי המידע, צריך להוסיף מרווחים ל-
RecyclerView. כדי לעשות את זה, מגדירים אתandroid:fitsSystemWindowsלערךtrueאו משתמשים ב-ViewCompat.setOnApplyWindowInsetsListener. - כדי לאפשר לפריטים ברשימה להופיע מתחת לסרגלי המידע בזמן הגלילה, מגדירים את
android:clipToPaddingכ-falseב-RecyclerView.
בסרטון הבא מוצג מכשיר RecyclerView כשהתצוגה מקצה לקצה מושבתת (מימין) ומופעלת (משמאל):
קוד לדוגמה של הוספת מודעה:
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; } );
קובץ ה-XML של RecyclerView:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent" />
מקורות מידע נוספים
למידע נוסף על בדיקות ב-Android, אפשר לעיין במקורות המידע הבאים.