ایجاد فهرستهای پویا با RecyclerView بخشی از Android Jetpack.
RecyclerView نمایش کارآمد مجموعههای بزرگ داده را آسان میکند. شما دادهها را ارائه میدهید و ظاهر هر مورد را تعریف میکنید، و کتابخانه RecyclerView عناصر را بهطور پویا درصورت نیاز ایجاد میکند.
همانطور که از نام آن پیداست، RecyclerView آن عناصر منفرد را بازیافت میکند. وقتی موردی از صفحه پیمایش میشود، RecyclerView نمای آن را ازبین نمیبرد. درعوض، RecyclerView از نما برای موارد جدیدی که به روی صفحه پیمایش شدهاند مجدداً استفاده میکند. RecyclerView عملکرد و پاسخگویی برنامهتان را بهبود میبخشد و مصرف برق را کاهش میدهد.
کلاسهای کلیدی
چندین کلاس باهم کار میکنند تا فهرست پویای شما را بسازند.
RecyclerViewViewGroupاست که حاوی نماهای مربوط به دادههای شما است. این عنصر خودش یک نما است، بنابراینRecyclerViewرا به همان روشی که هر عنصر میانای کاربر دیگری را اضافه میکنید، به چیدمانتان اضافه میکنید.هر عنصر جداگانه در فهرست با یک شیء نگهدارنده نما تعریف میشود. وقتی نگهدارنده نما ایجاد میشود، هیچ دادهای با آن مرتبط نیست. پساز ایجاد نگهدارنده نما،
RecyclerViewآن را به دادههایش مقید میکند. با گسترش دادنRecyclerView.ViewHolder، نگهدارنده نما را تعریف میکنید.RecyclerViewنماها را درخواست میکند و نماها را با فراخوانی روشها در آداپتور به دادههایشان متصل میکند. آداپتور را با گسترش دادنRecyclerView.Adapterتعریف میکنید.مدیر چیدمان عناصر تکی را در فهرستتان مرتب میکند. میتوانید از یکی از مدیران چیدمان ارائهشده توسط کتابخانه RecyclerView استفاده کنید، یا میتوانید مدیر چیدمان خودتان را تعریف کنید. همه مدیران چیدمان براساس کلاس انتزاعی
LayoutManagerکتابخانه هستند.
میتوانید ببینید که چگونه همه قطعات در برنامه نمونه RecyclerView (Kotlin) یا برنامه نمونه RecyclerView (Java) در کنار هم قرار میگیرند.
مراحل پیادهسازی RecyclerView
اگر میخواهید از RecyclerView استفاده کنید، باید چند کار را انجام دهید. این کارها بهطور مفصل در بخشهای زیر توضیح داده شدهاند.
تصمیم بگیرید فهرست یا جدول چگونه بهنظر برسد. معمولاً میتوانید از یکی از مدیران چیدمان استاندارد کتابخانه RecyclerView استفاده کنید.
ظاهر و رفتار هر عنصر در فهرست را طراحی کنید. براساس این طراحی، کلاس
ViewHolderرا گسترش دهید. نسخه شما ازViewHolderهمه عملکردهای لازم را برای موارد فهرستتان ارائه میدهد. نگهدارنده نمای شما یک پوشش در اطرافViewاست و آن نما توسطRecyclerViewمدیریت میشود.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با دادهها فراخوانی میکند. The method fetches the appropriate data and uses the data to fill in the view holder's layout. برای مثال، اگر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; } }
چیدمان هر مورد نمایشی، طبق معمول، در فایل چیدمان 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اعمال کنید. میتوانید این کار را با تنظیم کردن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; } );
RecyclerView XML:
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/my_recycler_view"
android:clipToPadding="false"
android:layout_width="match_parent"
android:layout_height="match_parent" />
منابع بیشتر
برای کسب اطلاعات بیشتر درباره آزمایش در Android، به منابع زیر مراجعه کنید.