ایجاد لیست‌های پویا با RecyclerView Part از Android Jetpack .

روش نوشتن را امتحان کنید
Jetpack Compose ابزار رابط کاربری پیشنهادی برای اندروید است. یاد بگیرید که چگونه با طرح‌بندی‌ها در Compose کار کنید.

RecyclerView نمایش کارآمد مجموعه‌های بزرگی از داده‌ها را آسان می‌کند. شما داده‌ها را ارائه می‌دهید و نحوه نمایش هر آیتم را تعریف می‌کنید، و کتابخانه RecyclerView به صورت پویا عناصر را در صورت نیاز ایجاد می‌کند.

همانطور که از نامش پیداست، RecyclerView آن عناصر را به صورت جداگانه بازیافت می‌کند . وقتی یک آیتم از صفحه خارج می‌شود، RecyclerView نمای آن را از بین نمی‌برد. در عوض، RecyclerView از نمای آیتم‌های جدیدی که روی صفحه پیمایش شده‌اند، دوباره استفاده می‌کند. RecyclerView عملکرد و پاسخگویی برنامه شما را بهبود می‌بخشد و مصرف برق را کاهش می‌دهد.

کلاس‌های کلیدی

چندین کلاس با هم کار می‌کنند تا لیست پویای شما را بسازند.

  • RecyclerView یک ViewGroup است که شامل viewهای مربوط به داده‌های شما می‌شود. این خودش یک view است، بنابراین شما RecyclerView به طرح‌بندی خود اضافه می‌کنید، همانطور که هر عنصر UI دیگری را اضافه می‌کنید.

  • هر عنصر جداگانه در لیست توسط یک شیء نگهدارنده نما تعریف می‌شود. وقتی نگهدارنده نما ایجاد می‌شود، هیچ داده‌ای به آن مرتبط نیست. پس از ایجاد نگهدارنده نما، RecyclerView آن را به داده‌هایش متصل می‌کند . شما نگهدارنده نما را با بسط دادن RecyclerView.ViewHolder تعریف می‌کنید.

  • RecyclerView با فراخوانی متدهایی در آداپتور، نماها را درخواست می‌کند و نماها را به داده‌هایشان متصل می‌کند. شما آداپتور را با ارث‌بری از RecyclerView.Adapter تعریف می‌کنید.

  • مدیر طرح‌بندی، عناصر منفرد موجود در لیست شما را مرتب می‌کند. می‌توانید از یکی از مدیران طرح‌بندی ارائه شده توسط کتابخانه RecyclerView استفاده کنید، یا می‌توانید خودتان یک مدیر طرح‌بندی تعریف کنید. همه مدیران طرح‌بندی بر اساس کلاس انتزاعی LayoutManager کتابخانه هستند.

می‌توانید ببینید که چگونه همه قطعات در برنامه نمونه RecyclerView (کاتلین) یا برنامه نمونه RecyclerView (جاوا) کنار هم قرار می‌گیرند.

مراحل پیاده‌سازی RecyclerView

اگر قصد استفاده از RecyclerView را دارید، چند کار وجود دارد که باید انجام دهید. این کارها در بخش‌های بعدی به تفصیل توضیح داده شده‌اند.

  1. تصمیم بگیرید که لیست یا شبکه چگونه به نظر برسد. معمولاً می‌توانید از یکی از ابزارهای مدیریت طرح‌بندی استاندارد کتابخانه RecyclerView استفاده کنید.

  2. طراحی کنید که هر عنصر در لیست چگونه به نظر برسد و رفتار کند. بر اساس این طراحی، کلاس ViewHolder را ارث بری کنید. نسخه ViewHolder شما تمام قابلیت‌ها را برای آیتم‌های لیست شما فراهم می‌کند. نگهدارنده نمای شما یک پوشش (wrapper) در اطراف یک View است و آن نما توسط RecyclerView مدیریت می‌شود.

  3. Adapter را تعریف کنید که داده‌های شما را با نماهای ViewHolder مرتبط می‌کند.

همچنین گزینه‌های سفارشی‌سازی پیشرفته‌ای وجود دارد که به شما امکان می‌دهد RecyclerView خود را دقیقاً مطابق با نیازهایتان تنظیم کنید.

طرح خود را برنامه ریزی کنید

آیتم‌های موجود در RecyclerView شما توسط یک کلاس LayoutManager مرتب می‌شوند. کتابخانه RecyclerView سه مدیر طرح‌بندی ارائه می‌دهد که رایج‌ترین موقعیت‌های طرح‌بندی را مدیریت می‌کنند:

  • LinearLayoutManager آیتم‌ها را در یک لیست تک‌بعدی مرتب می‌کند.
  • GridLayoutManager آیتم‌ها را در یک شبکه دوبعدی مرتب می‌کند:
    • اگر شبکه به صورت عمودی چیده شده باشد، GridLayoutManager سعی می‌کند تمام عناصر موجود در هر ردیف، عرض و ارتفاع یکسانی داشته باشند، اما ردیف‌های مختلف می‌توانند ارتفاع‌های متفاوتی داشته باشند.
    • اگر شبکه به صورت افقی چیده شده باشد، GridLayoutManager سعی می‌کند تمام عناصر موجود در هر ستون عرض و ارتفاع یکسانی داشته باشند، اما ستون‌های مختلف می‌توانند عرض‌های متفاوتی داشته باشند.
  • StaggeredGridLayoutManager مشابه GridLayoutManager است، اما الزامی ندارد که آیتم‌های یک ردیف ارتفاع یکسانی داشته باشند (برای شبکه‌های عمودی) یا آیتم‌های یک ستون عرض یکسانی داشته باشند (برای شبکه‌های افقی). نتیجه این است که آیتم‌های یک ردیف یا ستون می‌توانند نسبت به یکدیگر جابجا شوند.

شما همچنین باید طرح‌بندی تک تک آیتم‌ها را طراحی کنید. همانطور که در بخش بعدی توضیح داده شده است، هنگام طراحی نگهدارنده نما به این طرح‌بندی نیاز دارید.

آداپتور و نگهدارنده نمای خود را پیاده‌سازی کنید

پس از تعیین طرح‌بندی، باید Adapter و ViewHolder خود را پیاده‌سازی کنید. این دو کلاس با هم کار می‌کنند تا نحوه نمایش داده‌های شما را تعریف کنند. ViewHolder یک پوشش در اطراف View است که شامل طرح‌بندی برای یک آیتم خاص در لیست است. Adapter در صورت نیاز اشیاء ViewHolder را ایجاد می‌کند و همچنین داده‌ها را برای آن نماها تنظیم می‌کند. فرآیند مرتبط کردن نماها با داده‌هایشان ، اتصال (binding) نامیده می‌شود.

وقتی آداپتور خود را تعریف می‌کنید، سه متد کلیدی را نادیده می‌گیرید:

  • onCreateViewHolder() : RecyclerView هر زمان که نیاز به ایجاد یک ViewHolder جدید داشته باشد، این متد را فراخوانی می‌کند. این متد ViewHolder و View مرتبط با آن را ایجاد و مقداردهی اولیه می‌کند، اما محتوای view را پر نمی‌کند - ViewHolder هنوز به داده‌های خاصی متصل نشده است.

  • onBindViewHolder() : RecyclerView این متد را برای مرتبط کردن یک ViewHolder با داده‌ها فراخوانی می‌کند. این متد داده‌های مناسب را دریافت کرده و از داده‌ها برای پر کردن طرح‌بندی نگهدارنده‌ی نما استفاده می‌کند. برای مثال، اگر RecyclerView لیستی از نام‌ها را نمایش دهد، این متد ممکن است نام مناسب را در لیست پیدا کرده و ویجت TextView نگهدارنده‌ی نما را پر کند.

  • getItemCount() : RecyclerView این متد را برای دریافت اندازه مجموعه داده‌ها فراخوانی می‌کند. برای مثال، در یک برنامه دفترچه آدرس، این ممکن است تعداد کل آدرس‌ها باشد. RecyclerView از این برای تعیین زمانی که دیگر آیتمی برای نمایش وجود ندارد، استفاده می‌کند.

در اینجا یک مثال معمول از یک آداپتور ساده با یک ViewHolder تو در تو که لیستی از داده‌ها را نمایش می‌دهد، آورده شده است. در این حالت، RecyclerView یک لیست ساده از عناصر متنی را نمایش می‌دهد. به آداپتور، آرایه‌ای از رشته‌ها حاوی متن برای عناصر ViewHolder ارسال می‌شود.

کاتلین

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

}

جاوا

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;
    }
}

طرح‌بندی هر آیتم view، طبق معمول، در یک فایل طرح‌بندی 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 را نشان می‌دهد.

کاتلین

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

    }

}

جاوا

RecyclerView recyclerView = findViewById(R.id.recycler_view);
recyclerView.layoutManager = new LinearLayoutManager(this)
recyclerView.setAdapter(customAdapter);

این کتابخانه همچنین روش‌های زیادی برای سفارشی‌سازی پیاده‌سازی شما ارائه می‌دهد. برای اطلاعات بیشتر، به سفارشی‌سازی پیشرفته RecyclerView مراجعه کنید.

فعال کردن نمایشگر لبه به لبه

برای فعال کردن نمایش لبه به لبه برای RecyclerView ، این مراحل را دنبال کنید:

  • با فراخوانی تابع enableEdgeToEdge() یک نمایشگر لبه به لبه سازگار با نسخه‌های قبلی راه‌اندازی کنید.
  • اگر آیتم‌های لیست در ابتدا روی میله‌های سیستم همپوشانی دارند، روی RecyclerView درج (inset) اعمال کنید. می‌توانید این کار را با تنظیم android:fitsSystemWindows روی true یا با استفاده از ViewCompat.setOnApplyWindowInsetsListener انجام دهید.
  • با تنظیم android:clipToPadding روی false در RecyclerView ، به آیتم‌های لیست اجازه دهید هنگام اسکرول کردن، زیر نوارهای سیستم نمایش داده شوند.

ویدیوی زیر یک RecyclerView با نمایش لبه به لبه غیرفعال (چپ) و فعال (راست) نشان می‌دهد:

مثال کد درج:

کاتلین

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
  }
  

جاوا

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" />

منابع اضافی

برای اطلاعات بیشتر در مورد آزمایش در اندروید، به منابع زیر مراجعه کنید.

برنامه‌های نمونه