יצירת רשימות דינמיות באמצעות RecyclerView   חלק מ-Android Jetpack.

כדאי לנסות את התכונה 'כתיבה מהירה'
Jetpack Compose היא ערכת הכלים המומלצת לבניית ממשק משתמש ב-Android. איך עובדים עם פריסות ב-Compose

RecyclerView מאפשר להציג בקלות קבוצות גדולות של נתונים. אתם מספקים את הנתונים ומגדירים את המראה של כל פריט, וספריית RecyclerView יוצרת את הרכיבים באופן דינמי כשיש צורך בהם.

כפי שרומז השם, רכיב RecyclerView ממחזר את הרכיבים הבודדים האלה. כשגלילים פריטים מחוץ למסך, רכיב RecyclerView לא משמיד את התצוגה שלהם. במקום זאת, RecyclerView משתמש שוב בתצוגה לפריטים חדשים שגללו למסך. רכיב RecyclerView משפר את הביצועים ואת תגובת האפליקציה, וגם מפחית את צריכת החשמל.

כיתות מפתח

כמה כיתות פועלות יחד כדי ליצור את הרשימה הדינמית.

  • RecyclerView הוא ViewGroup שמכיל את התצוגות שמתאימות לנתונים שלכם. הוא עצמו תצוגה, כך שמוסיפים את RecyclerView למבנה כמו שמוסיפים כל רכיב אחר של ממשק המשתמש.

  • כל רכיב בנפרד ברשימה מוגדר על ידי אובייקט view holder. כשה-ViewHolder נוצר, לא משויכים אליו נתונים. אחרי שיוצרים את מחזיק התצוגה, ה-RecyclerView מקשר אותו לנתונים שלו. מגדירים את ה-ViewHolder על ידי הרחבה של RecyclerView.ViewHolder.

  • ה-RecyclerView מבקש תצוגות ומקשר את התצוגות לנתונים שלהן, על ידי קריאה לשיטות במתאם. מגדירים את המתאם על ידי הרחבה של RecyclerView.Adapter.

  • מנהל הפריסה מסדר את הרכיבים השונים ברשימה. אפשר להשתמש באחד מנהלי הפריסה שסופקו על ידי ספריית RecyclerView, או להגדיר מנהל משלכם. כל מנהלי הפריסות מבוססים על הכיתה המופשטת LayoutManager של הספרייה.

אתם יכולים לראות איך כל החלקים מתחברים באפליקציית הדוגמה של RecyclerView (Kotlin) או באפליקציית הדוגמה של RecyclerView (Java).

שלבים להטמעת RecyclerView

אם אתם מתכננים להשתמש ב-RecyclerView, יש כמה דברים שצריך לעשות. הם מוסברים בפירוט בקטעים הבאים.

  1. קובעים איך תיראה הרשימה או התצוגה של הרשת. בדרך כלל אפשר להשתמש באחד מנהלי הפריסה הרגילים של ספריית RecyclerView.

  2. עיצוב המראה וההתנהגות של כל רכיב ברשימה. על סמך העיצוב הזה, מרחיבים את המחלקה ViewHolder. הגרסה שלכם ל-ViewHolder מספקת את כל הפונקציונליות של הפריטים ברשימה. ה-ViewHolder הוא מעטפת של View, והתצוגה הזו מנוהלת על ידי RecyclerView.

  3. מגדירים את Adapter שמשויך לנתונים שלכם עם התצוגות ViewHolder.

יש גם אפשרויות התאמה אישית מתקדמות שמאפשרות להתאים את RecyclerView לצרכים הספציפיים שלכם.

תכנון הפריסה

הפריטים ב-RecyclerView מסודרים לפי הקלאס LayoutManager. בספרייה RecyclerView יש שלושה מנהלי פריסה שמטפלים בתרחישים הנפוצים ביותר של פריסה:

  • LinearLayoutManager מסדרת את הפריטים ברשימה חד-מימדית.
  • GridLayoutManager הפריטים מסודרים ברשת דו-מימדית:
    • אם התצוגה של התרשים היא אנכית, המערכת מנסה להגדיר לכל הרכיבים בכל שורה את אותו רוחב וגובה, אבל לגובה של שורות שונות יכולים להיות ערכים שונים.GridLayoutManager
    • אם התצוגה של הרשת היא אופקית, המערכת מנסה להגדיר לכל הרכיבים בכל עמודה את אותו רוחב וגובה, אבל לעמודות שונות יכולים להיות רוחבים שונים.GridLayoutManager
  • StaggeredGridLayoutManager דומה ל-GridLayoutManager, אבל לא נדרש שהפריטים בשורה יהיו באותו גובה (לרשתות אנכיות) או שהפריטים באותה עמודה יהיו באותו רוחב (לרשתות אופקיות). כתוצאה מכך, הפריטים בשורה או בעמודה יכולים להיות מוסטים זה מזה.

בנוסף, צריך לעצב את הפריסה של הפריטים הבודדים. תצטרכו את הפריסה הזו כשאתם מעצבים את ה-view holder, כפי שמתואר בקטע הבא.

הטמעת המתאם והמחזיק של התצוגה

אחרי שתבחרו את הפריסה, תצטרכו להטמיע את Adapter ו-ViewHolder. שתי הכיתות האלה פועלות יחד כדי לקבוע את אופן הצגת הנתונים. ה-ViewHolder הוא עטיפה של View שמכילה את הפריסה של פריט ספציפי ברשימה. ה-Adapter יוצר אובייקטים מסוג ViewHolder לפי הצורך, ומגדיר את הנתונים של התצוגות האלה. תהליך השיוך של תצוגות לנתונים שלהן נקרא קישור.

כשמגדירים את המתאם, משנים את ברירת המחדל של שלוש שיטות מפתח:

  • onCreateViewHolder(): ‏RecyclerView קורא לשיטה הזו בכל פעם שהוא צריך ליצור ViewHolder חדש. השיטה יוצרת ומפעילה את ViewHolder ואת View המשויך אליו, אבל לא ממלאת את התוכן של התצוגה – ViewHolder עדיין לא משויך לנתונים ספציפיים.

  • onBindViewHolder(): RecyclerView קורא ל-method הזה כדי לשייך ViewHolder לנתונים. השיטה מאחזרת את הנתונים המתאימים ומשתמשת בהם כדי למלא את הפריסה של מחזיק התצוגה. לדוגמה, אם ב-RecyclerView מוצגת רשימת שמות, השיטה עשויה למצוא את השם המתאים ברשימה ולמלא את הווידג'ט TextView של מחזיק התצוגה.

  • getItemCount(): RecyclerView קורא לשיטה הזו כדי לקבל את הגודל של מערך הנתונים. לדוגמה, באפליקציית אנשי קשר, זה יכול להיות המספר הכולל של הכתובות. מערכת 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.

מקורות מידע נוספים

למידע נוסף על בדיקה ב-Android, אפשר לעיין במקורות המידע הבאים.

אפליקציות לדוגמה