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

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

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

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

כיתות מפתח

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

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

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

  • ה-RecyclerView מבקש תצוגות מפורטות, ומקשר את התצוגות לנתונים שלהן באמצעות קריאה ל-methods במתאם. מגדירים את המתאם על ידי הרחבה של 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 קורא ל-method הזה בכל פעם שהוא צריך ליצור 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, אפשר לעיין במקורות המידע הבאים.

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