بسیاری از برنامه ها نیاز به نمایش مجموعه ای از آیتم ها دارند. این سند توضیح می دهد که چگونه می توانید این کار را به طور موثر در Jetpack Compose انجام دهید.
اگر میدانید که مورد استفاده شما نیازی به پیمایش ندارد، ممکن است بخواهید از یک Column
یا Row
ساده (بسته به جهت) استفاده کنید و محتوای هر مورد را با تکرار بر روی فهرست به روش زیر منتشر کنید:
@Composable fun MessageList(messages: List<Message>) { Column { messages.forEach { message -> MessageRow(message) } } }
میتوانیم با استفاده از اصلاحکننده verticalScroll()
Column
را قابل پیمایش کنیم.
لیست های تنبل
اگر نیاز به نمایش تعداد زیادی آیتم (یا لیستی با طول نامعلوم) دارید، استفاده از طرحبندی مانند Column
میتواند باعث مشکلات عملکرد شود، زیرا همه آیتمها تشکیل و چیده میشوند، خواه قابل مشاهده باشند یا نباشند.
Compose مجموعهای از مؤلفهها را فراهم میکند که فقط مواردی را که در نمای کامپوننت قابل مشاهده هستند، ترکیب و چیدمان میکنند. این مؤلفه ها عبارتند از LazyColumn
و LazyRow
.
همانطور که از نام آن پیداست، تفاوت LazyColumn
و LazyRow
در جهتی است که آنها آیتم های خود را در آن قرار می دهند و اسکرول می کنند. LazyColumn
یک لیست اسکرول عمودی تولید می کند و LazyRow
یک لیست اسکرول افقی تولید می کند.
اجزای Lazy با اکثر طرحبندیها در Compose متفاوت است. اجزای Lazy به جای پذیرش یک پارامتر بلوک محتوای @Composable
، که به برنامهها اجازه میدهد مستقیماً composableها را منتشر کنند، یک بلوک LazyListScope.()
ارائه میکنند. این بلوک LazyListScope
یک DSL را ارائه می دهد که به برنامه ها اجازه می دهد محتویات مورد را توصیف کنند . سپس مؤلفه Lazy مسئول افزودن محتوای هر آیتم مطابق با چیدمان و موقعیت اسکرول است.
LazyListScope
DSL
DSL LazyListScope
تعدادی توابع برای توصیف موارد در طرح ارائه می دهد. در ابتدایی ترین حالت، item()
یک آیتم را اضافه می کند و items(Int)
چندین آیتم را اضافه می کند:
LazyColumn { // Add a single item item { Text(text = "First item") } // Add 5 items items(5) { index -> Text(text = "Item: $index") } // Add another single item item { Text(text = "Last item") } }
همچنین تعدادی توابع افزودنی وجود دارد که به شما امکان می دهد مجموعه ای از موارد را اضافه کنید، مانند یک List
. این برنامههای افزودنی به ما امکان میدهند به راحتی مثال Column
خود را از بالا منتقل کنیم:
/** * import androidx.compose.foundation.lazy.items */ LazyColumn { items(messages) { message -> MessageRow(message) } }
همچنین یک نوع تابع پسوند items()
به نام itemsIndexed()
وجود دارد که ایندکس را فراهم می کند. لطفاً برای جزئیات بیشتر به مرجع LazyListScope
مراجعه کنید.
شبکه های تنبل
ترکیبپذیرهای LazyVerticalGrid
و LazyHorizontalGrid
از نمایش آیتمها در یک شبکه پشتیبانی میکنند. یک شبکه عمودی تنبل موارد خود را در یک محفظه قابل پیمایش عمودی، که در چندین ستون قرار دارد، نمایش میدهد، در حالی که شبکههای افقی تنبل همان رفتار را در محور افقی خواهند داشت.
گریدها دارای همان قابلیت های API قدرتمند لیست ها هستند و همچنین از یک DSL بسیار مشابه - LazyGridScope.()
برای توصیف محتوا استفاده می کنند.
پارامتر columns
در LazyVerticalGrid
و پارامتر rows
در LazyHorizontalGrid
نحوه تبدیل سلولها به ستونها یا ردیفها را کنترل میکنند. مثال زیر موارد را در یک شبکه نمایش می دهد، با استفاده از GridCells.Adaptive
برای تنظیم هر ستون حداقل 128.dp
عرض:
LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 128.dp) ) { items(photos) { photo -> PhotoItem(photo) } }
LazyVerticalGrid
به شما امکان می دهد یک عرض برای آیتم ها مشخص کنید، و سپس شبکه تا آنجا که ممکن است ستون ها را در خود جای دهد. هر پهنای باقیمانده پس از محاسبه تعداد ستونها، به طور مساوی بین ستونها توزیع میشود. این روش اندازهگیری تطبیقی برای نمایش مجموعههایی از آیتمها در اندازههای مختلف صفحه نمایش مفید است.
اگر تعداد دقیق ستونهای مورد استفاده را میدانید، میتوانید در عوض نمونهای از GridCells.Fixed
حاوی تعداد ستونهای مورد نیاز ارائه دهید.
اگر طراحی شما فقط به موارد خاصی نیاز دارد که ابعاد غیر استاندارد داشته باشند، می توانید از پشتیبانی شبکه برای ارائه دهانه ستون های سفارشی برای موارد استفاده کنید. دهانه ستون را با پارامتر span
item
و items
های LazyGridScope DSL
مشخص کنید. maxLineSpan
، یکی از مقادیر span scope، به ویژه هنگامی که از اندازه تطبیقی استفاده می کنید مفید است، زیرا تعداد ستون ها ثابت نیست. این مثال نحوه ارائه یک فاصله ردیف کامل را نشان می دهد:
LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 30.dp) ) { item(span = { // LazyGridItemSpanScope: // maxLineSpan GridItemSpan(maxLineSpan) }) { CategoryCard("Fruits") } // ... }
شبکه مبهم تنبل
LazyVerticalStaggeredGrid
و LazyHorizontalStaggeredGrid
قابل ترکیب هستند که به شما امکان می دهند یک شبکه اقلام با بارگذاری تنبل ایجاد کنید. یک شبکه پلکانی عمودی تنبل اقلام خود را در یک محفظه قابل پیمایش عمودی نشان میدهد که در چندین ستون قرار دارد و به آیتمها اجازه میدهد ارتفاعهای متفاوتی داشته باشند. شبکه های افقی تنبل رفتار یکسانی در محور افقی با موارد با عرض های مختلف دارند.
قطعه زیر یک مثال اساسی از استفاده از LazyVerticalStaggeredGrid
با عرض 200.dp
در هر مورد است:
LazyVerticalStaggeredGrid( columns = StaggeredGridCells.Adaptive(200.dp), verticalItemSpacing = 4.dp, horizontalArrangement = Arrangement.spacedBy(4.dp), content = { items(randomSizedPhotos) { photo -> AsyncImage( model = photo, contentScale = ContentScale.Crop, contentDescription = null, modifier = Modifier .fillMaxWidth() .wrapContentHeight() ) } }, modifier = Modifier.fillMaxSize() )
برای تنظیم تعداد ثابتی از ستونها، میتوانید به جای StaggeredGridCells.Adaptive از StaggeredGridCells.Adaptive
StaggeredGridCells.Fixed(columns)
استفاده کنید. این عرض موجود را بر تعداد ستونها (یا ردیفهای یک شبکه افقی) تقسیم میکند و هر مورد آن عرض (یا ارتفاع برای یک شبکه افقی) را میگیرد:
LazyVerticalStaggeredGrid( columns = StaggeredGridCells.Fixed(3), verticalItemSpacing = 4.dp, horizontalArrangement = Arrangement.spacedBy(4.dp), content = { items(randomSizedPhotos) { photo -> AsyncImage( model = photo, contentScale = ContentScale.Crop, contentDescription = null, modifier = Modifier .fillMaxWidth() .wrapContentHeight() ) } }, modifier = Modifier.fillMaxSize() )
بالشتک محتوا
گاهی اوقات شما نیاز به اضافه کردن بالشتک در لبه های محتوا دارید. کامپوننتهای تنبل به شما اجازه میدهند تا برخی از PaddingValues
به پارامتر contentPadding
ارسال کنید تا از این امر پشتیبانی کند:
LazyColumn( contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp), ) { // ... }
در این مثال، ما 16.dp
از padding را به لبه های افقی (چپ و راست) و سپس 8.dp
به بالا و پایین محتوا اضافه می کنیم.
لطفاً توجه داشته باشید که این بالشتک برای محتوا اعمال می شود، نه برای خود LazyColumn
. در مثال بالا، اولین آیتم دارای بالشتک 8.dp
به بالای آن، آخرین مورد 8.dp
به پایین خود اضافه میکند و همه موارد دارای 16.dp
در سمت چپ و راست خواهند بود.
فاصله محتوا
برای افزودن فاصله بین آیتم ها، می توانید از Arrangement.spacedBy()
استفاده کنید. مثال زیر 4.dp
فاصله بین هر مورد اضافه می کند:
LazyColumn( verticalArrangement = Arrangement.spacedBy(4.dp), ) { // ... }
به طور مشابه برای LazyRow
:
LazyRow( horizontalArrangement = Arrangement.spacedBy(4.dp), ) { // ... }
گریدها، هر دو ترتیب عمودی و افقی را می پذیرند:
LazyVerticalGrid( columns = GridCells.Fixed(2), verticalArrangement = Arrangement.spacedBy(16.dp), horizontalArrangement = Arrangement.spacedBy(16.dp) ) { items(photos) { item -> PhotoItem(item) } }
کلیدهای مورد
بهطور پیشفرض، وضعیت هر آیتم با موقعیت مورد در فهرست یا شبکه کلید میخورد. با این حال، در صورت تغییر مجموعه دادهها، این میتواند مشکلاتی را ایجاد کند، زیرا مواردی که موقعیت خود را تغییر میدهند، بهطور موثر حالت به خاطر سپردهشده را از دست میدهند. اگر سناریوی LazyRow
را در یک LazyColumn
تصور کنید، اگر ردیف موقعیت مورد را تغییر دهد، کاربر موقعیت اسکرول خود را در ردیف از دست خواهد داد.
برای مبارزه با این، می توانید یک کلید ثابت و منحصر به فرد برای هر آیتم تهیه کنید و یک بلوک برای پارامتر key
فراهم کنید. ارائه یک کلید پایدار، وضعیت مورد را قادر میسازد تا در میان تغییرات مجموعه دادهها یکسان باشد:
LazyColumn { items( items = messages, key = { message -> // Return a stable + unique key for the item message.id } ) { message -> MessageRow(message) } }
با ارائه کلیدها، به Compose کمک میکنید تا مرتبسازی مجدد را به درستی انجام دهد. به عنوان مثال، اگر مورد شما دارای وضعیت به خاطر سپردن باشد، کلیدهای تنظیم به Compose اجازه میدهد تا زمانی که موقعیت آن تغییر میکند، این حالت را همراه با آن مورد منتقل کند.
LazyColumn { items(books, key = { it.id }) { val rememberedValue = remember { Random.nextInt() } } }
با این حال، یک محدودیت در مورد انواعی که می توانید به عنوان کلید آیتم استفاده کنید وجود دارد. نوع کلید باید توسط Bundle
، مکانیسم Android برای حفظ حالتها هنگام ایجاد مجدد فعالیت، پشتیبانی شود. Bundle
از انواعی مانند primitives، enums یا Parcelables پشتیبانی می کند.
LazyColumn { items(books, key = { // primitives, enums, Parcelable, etc. }) { // ... } }
کلید باید توسط Bundle
پشتیبانی شود تا زمانی که Activity دوباره ایجاد میشود، یا حتی زمانی که از این مورد فاصله میگیرید و به عقب پیمایش میکنید، rememberSaveable
در داخل آیتم قابل تنظیم بازیابی شود.
LazyColumn { items(books, key = { it.id }) { val rememberedValue = rememberSaveable { Random.nextInt() } } }
انیمیشن های آیتم ها
اگر از ویجت RecyclerView استفاده کرده باشید، می دانید که تغییرات آیتم را به صورت خودکار متحرک می کند . طرحبندیهای تنبل عملکرد یکسانی را برای مرتبسازی مجدد اقلام ارائه میکنند. API ساده است - فقط باید اصلاح کننده animateItemPlacement
را روی محتوای آیتم تنظیم کنید:
LazyColumn { // It is important to provide a key to each item to ensure animateItem() works as expected. items(books, key = { it.id }) { Row(Modifier.animateItem()) { // ... } } }
در صورت نیاز، حتی می توانید مشخصات انیمیشن سفارشی را ارائه دهید:
LazyColumn { items(books, key = { it.id }) { Row( Modifier.animateItem( fadeInSpec = tween(durationMillis = 250), fadeOutSpec = tween(durationMillis = 100), placementSpec = spring(stiffness = Spring.StiffnessLow, dampingRatio = Spring.DampingRatioMediumBouncy) ) ) { // ... } } }
مطمئن شوید که کلیدهایی را برای آیتم های خود ارائه کرده اید تا موقعیت جدید عنصر جابجا شده را پیدا کنید.
سرصفحه های چسبنده (تجربی)
الگوی "هدر چسبنده" هنگام نمایش لیستی از داده های گروه بندی شده مفید است. در زیر میتوانید نمونهای از «فهرست مخاطبین» را ببینید که بر اساس حروف اول هر مخاطب گروهبندی شده است:
برای دستیابی به هدر چسبنده با LazyColumn
، میتوانید از تابع تجربی stickyHeader()
استفاده کنید و محتوای هدر را ارائه کنید:
@OptIn(ExperimentalFoundationApi::class) @Composable fun ListWithHeader(items: List<Item>) { LazyColumn { stickyHeader { Header() } items(items) { item -> ItemRow(item) } } }
برای دستیابی به یک لیست با سربرگ های متعدد، مانند مثال "فهرست مخاطبین" در بالا، می توانید انجام دهید:
// This ideally would be done in the ViewModel val grouped = contacts.groupBy { it.firstName[0] } @OptIn(ExperimentalFoundationApi::class) @Composable fun ContactsList(grouped: Map<Char, List<Contact>>) { LazyColumn { grouped.forEach { (initial, contactsForInitial) -> stickyHeader { CharacterHeader(initial) } items(contactsForInitial) { contact -> ContactListItem(contact) } } } }
واکنش به موقعیت اسکرول
بسیاری از برنامهها باید به تغییرات موقعیت اسکرول و چیدمان آیتم واکنش نشان دهند و گوش دهند. اجزای Lazy با بالا بردن LazyListState
از این مورد پشتیبانی میکنند:
@Composable fun MessageList(messages: List<Message>) { // Remember our own LazyListState val listState = rememberLazyListState() // Provide it to LazyColumn LazyColumn(state = listState) { // ... } }
برای موارد استفاده ساده، برنامهها معمولاً فقط باید اطلاعات مربوط به اولین مورد قابل مشاهده را بدانند. برای این LazyListState
خواص firstVisibleItemIndex
و firstVisibleItemScrollOffset
را ارائه می دهد.
اگر از مثال نمایش و پنهان کردن یک دکمه بر اساس اینکه آیا کاربر از اولین مورد عبور کرده است استفاده کنیم:
@Composable fun MessageList(messages: List<Message>) { Box { val listState = rememberLazyListState() LazyColumn(state = listState) { // ... } // Show the button if the first visible item is past // the first item. We use a remembered derived state to // minimize unnecessary compositions val showButton by remember { derivedStateOf { listState.firstVisibleItemIndex > 0 } } AnimatedVisibility(visible = showButton) { ScrollToTopButton() } } }
خواندن وضعیت به طور مستقیم در ترکیب زمانی مفید است که شما نیاز به به روز رسانی سایر کامپوزیشن های رابط کاربری دارید، اما سناریوهایی نیز وجود دارد که لازم نیست رویداد در همان ترکیب انجام شود. یک مثال رایج در این مورد ارسال یک رویداد تجزیه و تحلیل زمانی است که کاربر از نقطه خاصی عبور کرده است. برای مدیریت موثر این موضوع، میتوانیم از snapshotFlow()
استفاده کنیم:
val listState = rememberLazyListState() LazyColumn(state = listState) { // ... } LaunchedEffect(listState) { snapshotFlow { listState.firstVisibleItemIndex } .map { index -> index > 0 } .distinctUntilChanged() .filter { it } .collect { MyAnalyticsService.sendScrolledPastFirstItemEvent() } }
LazyListState
همچنین اطلاعاتی را در مورد تمام مواردی که در حال حاضر نمایش داده می شوند و محدوده آنها روی صفحه، از طریق ویژگی layoutInfo
ارائه می دهد. برای اطلاعات بیشتر به کلاس LazyListLayoutInfo
مراجعه کنید.
کنترل موقعیت اسکرول
علاوه بر واکنش به موقعیت اسکرول، برای برنامهها نیز مفید است که بتوانند موقعیت اسکرول را نیز کنترل کنند. LazyListState
از طریق تابع scrollToItem()
که "فورا" موقعیت اسکرول را می گیرد و animateScrollToItem()
که با استفاده از یک انیمیشن (که به عنوان اسکرول صاف نیز شناخته می شود) اسکرول می کند، پشتیبانی می کند:
@Composable fun MessageList(messages: List<Message>) { val listState = rememberLazyListState() // Remember a CoroutineScope to be able to launch val coroutineScope = rememberCoroutineScope() LazyColumn(state = listState) { // ... } ScrollToTopButton( onClick = { coroutineScope.launch { // Animate scroll to the first item listState.animateScrollToItem(index = 0) } } ) }
مجموعه داده های بزرگ (صفحه بندی)
کتابخانه Paging به برنامهها امکان میدهد از فهرستهای بزرگی از آیتمها پشتیبانی کنند، در صورت لزوم، تکههای کوچکی از فهرست را بارگیری و نمایش دهند. Paging 3.0 و جدیدتر از طریق کتابخانه androidx.paging:paging-compose
پشتیبانی Compose را ارائه میکند.
برای نمایش لیستی از محتوای صفحهشده، میتوانیم از تابع پسوند collectAsLazyPagingItems()
استفاده کنیم و سپس LazyPagingItems
بازگشتی را به items()
در LazyColumn
خود منتقل کنیم. مشابه پشتیبانی صفحهبندی در نماها، میتوانید در حین بارگیری دادهها، با بررسی null
بودن item
، متغیرهایی را نمایش دهید:
@Composable fun MessageList(pager: Pager<Int, Message>) { val lazyPagingItems = pager.flow.collectAsLazyPagingItems() LazyColumn { items( lazyPagingItems.itemCount, key = lazyPagingItems.itemKey { it.id } ) { index -> val message = lazyPagingItems[index] if (message != null) { MessageRow(message) } else { MessagePlaceholder() } } } }
نکاتی در مورد استفاده از طرح بندی های تنبل
چند نکته وجود دارد که می توانید برای اطمینان از اینکه چیدمان های تنبل شما همانطور که در نظر گرفته شده است کار می کنند، در نظر بگیرید.
از استفاده از موارد با اندازه 0 پیکسل خودداری کنید
این ممکن است در سناریوهایی اتفاق بیفتد که، برای مثال، انتظار دارید به طور ناهمزمان برخی از دادهها مانند تصاویر را بازیابی کنید تا موارد فهرست خود را در مرحله بعد پر کنید. این باعث میشود که طرح تنبل تمام موارد خود را در اولین اندازهگیری ترکیب کند، زیرا ارتفاع آنها 0 پیکسل است و میتواند همه آنها را در نمای دید قرار دهد. هنگامی که موارد بارگیری شدند و ارتفاع آنها افزایش یافت، طرحبندیهای تنبل همه موارد دیگری را که برای اولین بار بهطور غیرضروری نوشته شدهاند، کنار میگذارند، زیرا در واقع نمیتوانند با درگاه دید مطابقت داشته باشند. برای جلوگیری از این امر، باید اندازه پیشفرض را روی آیتمهای خود تنظیم کنید تا طرحبندی Lazy بتواند محاسبه درستی از تعداد آیتمهایی که در واقع میتوانند در ویوپورت جا شوند را انجام دهد:
@Composable fun Item(imageUrl: String) { AsyncImage( model = rememberAsyncImagePainter(model = imageUrl), modifier = Modifier.size(30.dp), contentDescription = null // ... ) }
هنگامی که اندازه تقریبی موارد خود را پس از بارگیری ناهمزمان دادهها میدانید، یک تمرین خوب این است که اطمینان حاصل کنید که اندازه اقلام شما قبل و بعد از بارگذاری ثابت باقی میماند، به عنوان مثال، با افزودن چند متغیر مکان. این به حفظ موقعیت صحیح اسکرول کمک می کند.
از تودرتو کردن اجزای قابل پیمایش در یک جهت خودداری کنید
این فقط برای مواردی اعمال میشود که کودکان قابل پیمایش را بدون اندازه از پیش تعریف شده در داخل والد قابل پیمایش هم جهت دیگری قرار میدهند. برای مثال، تلاش برای تودرتو کردن یک ستون LazyColumn
بدون ارتفاع ثابت در داخل یک Column
والد قابل پیمایش عمودی:
// throws IllegalStateException Column( modifier = Modifier.verticalScroll(state) ) { LazyColumn { // ... } }
در عوض، با قرار دادن همه اجزای سازنده خود در یک LazyColumn
والد و استفاده از DSL آن برای ارسال انواع مختلف محتوا، می توان به همان نتیجه دست یافت. این امر امکان انتشار آیتم های منفرد و همچنین چندین آیتم لیست را در یک مکان فراهم می کند:
LazyColumn { item { Header() } items(data) { item -> PhotoItem(item) } item { Footer() } }
به خاطر داشته باشید که مواردی که در آن طرحبندیهای جهت مختلف را تودرتو میکنید، برای مثال، یک Row
والد قابل پیمایش و یک LazyColumn
فرزند، مجاز هستند:
Row( modifier = Modifier.horizontalScroll(scrollState) ) { LazyColumn { // ... } }
و همچنین مواردی که هنوز از طرحبندیهای جهت یکسان استفاده میکنید، اما اندازه ثابتی را نیز برای فرزندان تودرتو تنظیم میکنید:
Column( modifier = Modifier.verticalScroll(scrollState) ) { LazyColumn( modifier = Modifier.height(200.dp) ) { // ... } }
مراقب قرار دادن چندین عنصر در یک آیتم باشید
در این مثال، آیتم دوم لامبدا 2 مورد را در یک بلوک منتشر می کند:
LazyVerticalGrid( columns = GridCells.Adaptive(100.dp) ) { item { Item(0) } item { Item(1) Item(2) } item { Item(3) } // ... }
طرحبندیهای تنبل همانطور که انتظار میرود این کار را انجام میدهند - آنها عناصر را یکی پس از دیگری طوری قرار میدهند که گویی آیتمهای متفاوتی هستند. با این حال، انجام این کار چند مشکل دارد.
هنگامی که چندین عنصر به عنوان بخشی از یک آیتم منتشر می شوند، آنها به عنوان یک موجودیت مدیریت می شوند، به این معنی که دیگر نمی توان آنها را به صورت جداگانه ترکیب کرد. اگر یک عنصر روی صفحه قابل مشاهده باشد، تمام عناصر مربوط به مورد باید ترکیب و اندازه گیری شوند. اگر بیش از حد استفاده شود، می تواند به عملکرد آسیب برساند. در حالت شدید قرار دادن همه عناصر در یک آیتم، هدف استفاده از طرحبندی Lazy را کاملاً از بین میبرد. جدا از مشکلات بالقوه عملکرد، قرار دادن عناصر بیشتر در یک آیتم با scrollToItem()
و animateScrollToItem()
نیز تداخل خواهد داشت.
با این حال، موارد استفاده معتبری برای قرار دادن چندین عنصر در یک آیتم وجود دارد، مانند داشتن تقسیم کننده ها در یک لیست. شما نمی خواهید تقسیم کننده ها شاخص های پیمایش را تغییر دهند، زیرا نباید آنها را عناصر مستقل در نظر گرفت. همچنین عملکرد تحت تأثیر قرار نمی گیرد زیرا تقسیم کننده ها کوچک هستند. یک تقسیمکننده احتمالاً باید قبل از اینکه مورد قابل مشاهده باشد قابل مشاهده باشد، بنابراین آنها میتوانند بخشی از مورد قبلی باشند:
LazyVerticalGrid( columns = GridCells.Adaptive(100.dp) ) { item { Item(0) } item { Item(1) Divider() } item { Item(2) } // ... }
استفاده از ترتیبات سفارشی را در نظر بگیرید
معمولاً لیست های تنبل آیتم های زیادی دارند و بیش از اندازه ظرف پیمایش را اشغال می کنند. با این حال، زمانی که لیست شما با آیتم های کمی پر شده است، طراحی شما می تواند الزامات خاص تری برای نحوه قرارگیری این موارد در ویوپورت داشته باشد.
برای رسیدن به این هدف، می توانید از Arrangement
عمودی سفارشی استفاده کنید و آن را به LazyColumn
منتقل کنید. در مثال زیر، شی TopWithFooter
فقط باید متد arrange
را پیاده سازی کند. ابتدا موارد را یکی پس از دیگری قرار می دهد. ثانیاً، اگر مجموع ارتفاع استفاده شده کمتر از ارتفاع نمای پورت باشد، فوتر را در پایین قرار می دهد:
object TopWithFooter : Arrangement.Vertical { override fun Density.arrange( totalSize: Int, sizes: IntArray, outPositions: IntArray ) { var y = 0 sizes.forEachIndexed { index, size -> outPositions[index] = y y += size } if (y < totalSize) { val lastIndex = outPositions.lastIndex outPositions[lastIndex] = totalSize - sizes.last() } } }
اضافه کردن contentType
را در نظر بگیرید
با شروع Compose 1.2، به منظور به حداکثر رساندن عملکرد Lazy Lazy خود، contentType
به لیست ها یا شبکه های خود اضافه کنید. این به شما امکان میدهد نوع محتوا را برای هر مورد از طرحبندی مشخص کنید، در مواردی که فهرست یا شبکهای متشکل از چندین نوع مختلف از آیتمها را میسازید:
LazyColumn { items(elements, contentType = { it.type }) { // ... } }
هنگامی که contentType
را ارائه میکنید، Compose میتواند از ترکیببندیها فقط بین موارد از همان نوع استفاده مجدد کند. از آنجایی که استفاده مجدد هنگام نوشتن موارد با ساختار مشابه کارآمدتر است، ارائه انواع محتوا تضمین میکند که Compose سعی نمیکند یک مورد از نوع A را روی یک مورد کاملاً متفاوت از نوع B بنویسد. این به حداکثر رساندن مزایای استفاده مجدد از ترکیب و عملکرد طرح تنبل شما.
اندازه گیری عملکرد
شما فقط میتوانید عملکرد یک طرحبندی Lazy را هنگام اجرا در حالت انتشار و با فعال بودن بهینهسازی R8 بهطور قابل اعتماد اندازهگیری کنید. در ساختهای اشکالزدایی، پیمایش طرحبندی تنبل ممکن است کندتر به نظر برسد. برای اطلاعات بیشتر در این مورد، Compose performance را بخوانید.
{% کلمه به کلمه %}برای شما توصیه می شود
- توجه: وقتی جاوا اسکریپت خاموش است، متن پیوند نمایش داده می شود
-
RecyclerView
به لیست Lazy منتقل کنید - حالت رابط کاربری را در Compose ذخیره کنید
- Kotlin برای Jetpack Compose