ایجاد لیستهای پویا با RecyclerView Part از Android Jetpack .
RecyclerView نمایش کارآمد مجموعههای بزرگی از دادهها را آسان میکند. شما دادهها را ارائه میدهید و نحوه نمایش هر آیتم را تعریف میکنید، و کتابخانه RecyclerView به صورت پویا عناصر را در صورت نیاز ایجاد میکند.
همانطور که از نامش پیداست، RecyclerView آن عناصر را به صورت جداگانه بازیافت میکند . وقتی یک آیتم از صفحه خارج میشود، RecyclerView نمای آن را از بین نمیبرد. در عوض، RecyclerView از نمای آیتمهای جدیدی که روی صفحه پیمایش شدهاند، دوباره استفاده میکند. RecyclerView عملکرد و پاسخگویی برنامه شما را بهبود میبخشد و مصرف برق را کاهش میدهد.
کلاسهای کلیدی
چندین کلاس با هم کار میکنند تا لیست پویای شما را بسازند.
RecyclerViewیکViewGroupاست که شامل viewهای مربوط به دادههای شما میشود. این خودش یک view است، بنابراین شماRecyclerViewبه طرحبندی خود اضافه میکنید، همانطور که هر عنصر UI دیگری را اضافه میکنید.هر عنصر جداگانه در لیست توسط یک شیء نگهدارنده نما تعریف میشود. وقتی نگهدارنده نما ایجاد میشود، هیچ دادهای به آن مرتبط نیست. پس از ایجاد نگهدارنده نما،
RecyclerViewآن را به دادههایش متصل میکند . شما نگهدارنده نما را با بسط دادنRecyclerView.ViewHolderتعریف میکنید.RecyclerViewبا فراخوانی متدهایی در آداپتور، نماها را درخواست میکند و نماها را به دادههایشان متصل میکند. شما آداپتور را با ارثبری ازRecyclerView.Adapterتعریف میکنید.مدیر طرحبندی، عناصر منفرد موجود در لیست شما را مرتب میکند. میتوانید از یکی از مدیران طرحبندی ارائه شده توسط کتابخانه RecyclerView استفاده کنید، یا میتوانید خودتان یک مدیر طرحبندی تعریف کنید. همه مدیران طرحبندی بر اساس کلاس انتزاعی
LayoutManagerکتابخانه هستند.
میتوانید ببینید که چگونه همه قطعات در برنامه نمونه RecyclerView (کاتلین) یا برنامه نمونه RecyclerView (جاوا) کنار هم قرار میگیرند.
مراحل پیادهسازی RecyclerView
اگر قصد استفاده از RecyclerView را دارید، چند کار وجود دارد که باید انجام دهید. این کارها در بخشهای بعدی به تفصیل توضیح داده شدهاند.
تصمیم بگیرید که لیست یا شبکه چگونه به نظر برسد. معمولاً میتوانید از یکی از ابزارهای مدیریت طرحبندی استاندارد کتابخانه RecyclerView استفاده کنید.
طراحی کنید که هر عنصر در لیست چگونه به نظر برسد و رفتار کند. بر اساس این طراحی، کلاس
ViewHolderرا ارث بری کنید. نسخهViewHolderشما تمام قابلیتها را برای آیتمهای لیست شما فراهم میکند. نگهدارنده نمای شما یک پوشش (wrapper) در اطراف یکViewاست و آن نما توسطRecyclerViewمدیریت میشود.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" />
منابع اضافی
برای اطلاعات بیشتر در مورد آزمایش در اندروید، به منابع زیر مراجعه کنید.
