إنشاء قوائم ديناميكية باستخدام RecyclerView   جزء من Android Jetpack.

تجربة ميزة "الكتابة"
‫Jetpack Compose هي مجموعة أدوات واجهة المستخدم المُقترَحة لنظام التشغيل Android. تعرَّف على كيفية العمل مع التنسيقات في ميزة "الإنشاء".

تسهّل فئة RecyclerView عرض مجموعات كبيرة من البيانات بكفاءة. يمكنك تقديم البيانات وتحديد مظهر كل عنصر، وتنشئ مكتبة RecyclerView العناصر ديناميكيًا عند الحاجة إليها.

وكما يشير الاسم، فإنّ RecyclerView يعيد استخدام هذه العناصر الفردية. عندما يتم الانتقال إلى العنصر خارج الشاشة، لا يزيل RecyclerView طريقة العرض الخاصة به. بدلاً من ذلك، تتم إعادة استخدام عرض RecyclerView للعناصر الجديدة التي تم الانتقال إليها على الشاشة. تحسِّن RecyclerView من الأداء وسرعة استجابة تطبيقك، كما تسهم في خفض استهلاك الطاقة.

الفئات الرئيسية

تعمل عدة فئات معًا لإنشاء قائمتك الديناميكية.

  • RecyclerView هو ViewGroup الذي يحتوي على المشاهدات المتوافقة مع بياناتك. وهو طريقة عرض بحد ذاته، لذا يمكنك إضافة RecyclerView إلى التنسيق بالطريقة نفسها التي تُضيف بها أي عنصر آخر لواجهة المستخدم.

  • يتم تحديد كل عنصر فردي في القائمة من خلال عنصر حامل عرض. عند إنشاء حامل العرض، لا يكون لديه أي بيانات مرتبطة به. بعد إنشاء حامل العرض، يربطه RecyclerView ببياناته. يمكنك تحديد حامل العرض من خلال توسيع RecyclerView.ViewHolder.

  • يطلب RecyclerView طرق العرض ويربطها ببياناتها، من خلال استدعاء الطرق في المحوِّل. يمكنك تحديد المحوِّل من خلال توسيع RecyclerView.Adapter.

  • يدير مدير التنسيق العناصر الفردية في قائمتك. يمكنك استخدام أحد مدراء التنسيقات المقدَّمة من مكتبة RecyclerView، أو يمكنك تحديد مدير التنسيق الخاص بك. تستند جميع أدوات إدارة التنسيق إلى الفئة المجردة LayoutManager في المكتبة.

يمكنك الاطّلاع على كيفية ملاءمة كل القطع مع بعضها في نموذج تطبيق RecyclerView (Kotlin) أو نموذج تطبيق RecyclerView (Java).

خطوات تنفيذ RecyclerView

إذا كنت ستستخدم RecyclerView، هناك بعض الإجراءات التي يجب اتّخاذها. وسيتم شرحها بالتفصيل في الأقسام التالية.

  1. حدِّد شكل القائمة أو الشبكة. في العادة، يمكنك استخدام أحد مدراء التنسيق العاديين في مكتبة RecyclerView.

  2. تصميم مظهر كل عنصر في القائمة وطريقة تفاعله استنادًا إلى هذا التصميم، يمكنك توسيع فئة ViewHolder. يقدّم إصدارك من ViewHolder جميع الوظائف لعناصر قائمتك. حامل العرض هو عنصر ملفوف حول View، وتتم إدارة هذا العرض من خلال RecyclerView.

  3. حدِّد Adapter الذي يربط بياناتك بعروض ViewHolder.

تتوفّر أيضًا خيارات تخصيص متقدّمة تتيح لك تخصيص RecyclerView وفقًا لاحتياجاتك الدقيقة.

التخطيط لتصميم التطبيق

يتم ترتيب العناصر في RecyclerView حسب ملف شخصي LayoutManager. توفّر مكتبة RecyclerView ثلاثة مدراء تنسيق، وهم يتعاملون مع حالات التنسيق الأكثر شيوعًا:

  • LinearLayoutManager يُرتِّب العناصر في قائمة أحادية البعد.
  • GridLayoutManager يُرتِّب هذا الخيار العناصر في شبكة ثنائية الأبعاد:
    • إذا تم ترتيب الشبكة عموديًا، يحاول GridLayoutManager جعل كل العناصر في كل صف لها العرض والارتفاع نفسهما، ولكن يمكن أن يكون للصفوف المختلفة ارتفاعات مختلفة.
    • إذا تم ترتيب الشبكة أفقيًا، يحاول GridLayoutManager جعل كل العناصر في كل عمود لها العرض والارتفاع نفسهما، ولكن يمكن أن يكون لأعمدة مختلفة عرض مختلف.
  • StaggeredGridLayoutManager يشبه GridLayoutManager، ولكنّه لا يتطلّب أن يكون للعناصر في الصف الارتفاع نفسه (للشبكات العمودية) أو أن يكون للعناصر في العمود نفسه العرض نفسه (للشبكات الأفقية). والنتيجة هي أنّ العناصر في صف أو عمود قد تنتهي في مواضع مختلفة عن بعضها.

عليك أيضًا تصميم تنسيق العناصر الفردية. ستحتاج إلى هذا الترتيب عند تصميم حامل العرض، كما هو موضّح في القسم التالي.

تركيب المحوِّل وحامل الشاشة

بعد تحديد التنسيق، عليك تنفيذ Adapter و ViewHolder. تعمل هاتان الفئتان معًا لتحديد كيفية عرض بياناتك. ViewHolder هو عنصر ملفوف حول View يحتوي على تنسيق عنصر فردي في القائمة. ينشئ Adapter ViewHolder عناصر حسب الحاجة ويضبط أيضًا البيانات لهذه العروض. تُعرف عملية ربط طرق العرض ببياناتها باسم الربط.

عند تحديد المحوِّل، يمكنك إلغاء ثلاث طرق رئيسية:

  • onCreateViewHolder(): يُطلِق RecyclerView هذه الطريقة متى دعت الحاجة إلى إنشاء ViewHolder جديد. تنشئ الطريقة العنصر ViewHolder وView المرتبط به وتُنشئهما، ولكنّها لا تملأ محتوًى في العرض، لأنّه لم يتم ربط العنصر ViewHolder بعد ببيانات معيّنة.

  • onBindViewHolder(): يُطلِق RecyclerView هذه الطريقة لربط 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، يمكنك الرجوع إلى المراجع التالية.

أمثلة على التطبيقات