באפליקציות רבות צריך להציג אוספים של פריטים. במאמר הזה נסביר איך לעשות זאת ביעילות ב-Jetpack Compose.
אם אתם יודעים שבתרחיש לדוגמה שלכם אין צורך בגלילה, תוכלו להשתמש ב-Column
או ב-Row
(בהתאם לכיוון) ולהפיק את התוכן של כל פריט על ידי איטרציה ברשימה באופן הבא:
@Composable fun MessageList(messages: List<Message>) { Column { messages.forEach { message -> MessageRow(message) } } }
אפשר להפוך את Column
לגלילה באמצעות המשתנה המשנה verticalScroll()
.
רשימות עצלות
אם אתם צריכים להציג מספר גדול של פריטים (או רשימה באורך לא ידוע), שימוש בפריסה כמו Column
עלול לגרום לבעיות בביצועים, כי כל הפריטים יתוכננו ויוצגו, גם אם הם לא גלויים.
Compose מספק קבוצה של רכיבים שמרכיבים ומציבים רק פריטים שגלויים באזור התצוגה של הרכיב. הרכיבים האלה כוללים את LazyColumn
ואת LazyRow
.
כפי שרואים מהשם, ההבדל בין LazyColumn
לבין LazyRow
הוא בכיוון שבו הפריטים מוצגים והגלילה מתבצעת. LazyColumn
יוצר רשימה עם גלילה אנכית, ו-LazyRow
יוצר רשימה עם גלילה אופקית.
הרכיבים הלא פעילים שונים מרוב הפריסות ב-Compose. במקום לקבל פרמטר של חסימה של תוכן @Composable
, שמאפשר לאפליקציות להפיק ישירות רכיבים שניתנים לשילוב, הרכיבים הלא פעילים מספקים בלוק LazyListScope.()
. הבלוק LazyListScope
הזה כולל DSL שמאפשר לאפליקציות לתאר את תוכן הפריט. לאחר מכן, הרכיב הלא-אקטיבי אחראי להוספת התוכן של כל פריט בהתאם לפריסה ולמיקום הגלילה.
DSL: LazyListScope
ה-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
תומכים בהצגת פריטים בתצוגת רשת. בתצוגת רשת אנכית עם Lazy, הפריטים יוצגו במארז שאפשר לגלול בו אנכית, לאורך כמה עמודות. בתצוגת רשת אופקית עם Lazy, ההתנהגות תהיה זהה בציר האופקי.
לרשתות יש אותן יכולות 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
של השיטות LazyGridScope DSL
item
ו-items
.
maxLineSpan
, אחד מהערכים של היקף הטווח, שימושי במיוחד כשמשתמשים בשינוי גודל אדפטיבי, כי מספר העמודות לא קבוע.
בדוגמה הזו מוסבר איך לציין טווח שורה מלא:
LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 30.dp) ) { item(span = { // LazyGridItemSpanScope: // maxLineSpan GridItemSpan(maxLineSpan) }) { CategoryCard("Fruits") } // ... }
רשת מדורגת
LazyVerticalStaggeredGrid
ו-LazyHorizontalStaggeredGrid
הם תכנים קומפוזביליים שמאפשרים ליצור רשת של פריטים בטעינה מדורגת.
בתצוגת רשת אנכית מדורגת עצלה, הפריטים מוצגים בקונטיינר שאפשר לגלול בו אנכית, והוא משתרע על פני כמה עמודות ומאפשר לפריטים נפרדים להיות בגבהים שונים. לרשתות אופקיות עם פריסת Lazy יש אותה התנהגות בציר האופק עם פריטים ברוחב שונה.
קטע הקוד הבא הוא דוגמה בסיסית לשימוש ב-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.Fixed(columns)
במקום ב-StaggeredGridCells.Adaptive
.
המערכת מחלקת את הרוחב הזמין במספר העמודות (או השורות, אם מדובר בתצוגת רשת אופקית), וכל פריט תופס את הרוחב הזה (או את הגובה, אם מדובר בתצוגת רשת אופקית):
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
לקצוות האופקיים (שמאל וימין), ולאחר מכן 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
תומך בסוגי נתונים כמו פרימיטיבים, משתני enum או Parcelables.
LazyColumn { items(books, key = { // primitives, enums, Parcelable, etc. }) { // ... } }
המפתח צריך להיות נתמך על ידי Bundle
כדי שאפשר יהיה לשחזר את rememberSaveable
בתוך הפריט שאפשר ליצור ממנו קומפוזיציה כשהפעילות נוצרת מחדש, או אפילו כשגוללים מהפריט הזה וחוזרים אליו.
LazyColumn { items(books, key = { it.id }) { val rememberedValue = rememberSaveable { Random.nextInt() } } }
אנימציות של פריטים
אם השתמשתם בווידג'ט RecyclerView, אתם יודעים שהוא מפעיל אנימציה לשינויים בפריטים באופן אוטומטי.
בפריטי עיצוב עם טעינה מדורגת יש את אותה פונקציונליות גם כשמשנים את הסדר של הפריטים.
ה-API פשוט – צריך רק להגדיר את המשתנה animateItem
לתוכן הפריט:
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) } } ) }
קבוצות נתונים גדולות (דפים)
ספריית הגיליון מאפשרת לאפליקציות לתמוך ברשימות גדולות של פריטים, ולטעון ולהציג קטעים קטנים של הרשימה לפי הצורך. הקידוד בגרסה 3.0 ואילך מספק תמיכה בכתיבה דרך הספרייה androidx.paging:paging-compose
.
כדי להציג רשימה של תוכן שמחולק לדפים, אפשר להשתמש בפונקציית התוסף collectAsLazyPagingItems()
, ולאחר מכן להעביר את הערך המוחזר LazyPagingItems
אל items()
ב-LazyColumn
. בדומה לתמיכה בהחלפה בתצוגות, אפשר להציג placeholders בזמן טעינת הנתונים. לשם כך, בודקים אם הערך של item
הוא null
:
@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 פיקסלים והוא עשוי להתאים לכולם באזור התצוגה. אחרי שהפריטים נטענים והגובה שלהם מתרחב, התצוגה המפורטת עם פריטים נטענים באיטרציה אחת תשליך את כל הפריטים האחרים שהיו צריכים להיבנות בפעם הראשונה ללא צורך, כי הם לא יכולים להתאים למסך. כדי למנוע זאת, צריך להגדיר גודל ברירת מחדל לפריטים, כדי שהפריסה עם האיטרציה האיטית תוכל לבצע את החישוב הנכון של מספר הפריטים שיכולים להיכנס באזור התצוגה:
@Composable fun Item(imageUrl: String) { AsyncImage( model = rememberAsyncImagePainter(model = imageUrl), modifier = Modifier.size(30.dp), contentDescription = null // ... ) }
אחרי שבודקים את הגודל המשוער של הפריטים אחרי שהנתונים נטענים באופן אסינכרוני, כדאי לוודא שגודל הפריטים נשאר ללא שינוי לפני ואחרי הטעינה, למשל על ידי הוספת placeholders. כך תוכלו לשמור על מיקום הגלילה הנכון.
הימנעו מהטמעת רכיבים שאפשר לגלול אותם באותו כיוון
הכלל הזה חל רק במקרים שבהם תוחמים רכיבי צאצאים שניתן לגלול בהם ללא גודל מוגדר מראש בתוך רכיב הורה אחר שניתן לגלול בו באותו כיוון. לדוגמה, ניסיון להטמיע רכיב 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) } // ... }
פריסות 'לאט' יטפלו בבעיה הזו כצפוי – הן יפרסנו את הרכיבים אחד אחרי השני כאילו מדובר בפריטים שונים. עם זאת, יש כמה בעיות בכך.
כשמפיצים כמה רכיבים כחלק מפריט אחד, הם מטופלים כישות אחת, כלומר אי אפשר יותר ליצור מהם יצירה בנפרד. אם אלמנט אחד מופיע במסך, צריך ליצור ולמדוד את כל הרכיבים התואמים לפריט. שימוש מוגזם עלול לפגוע בביצועים. במקרה קיצוני שבו כל הרכיבים נמצאים בפריט אחד, המשמעות היא שכל העניין של שימוש בפריסות 'עיכוב טעינה' מבוטל. מלבד בעיות פוטנציאליות בביצועים, הוספת רכיבים נוספים לפריט אחד תפריע גם ל-scrollToItem()
ול-animateScrollToItem()
.
עם זאת, יש תרחישים לדוגמה תקינים להצבת רכיבים מרובים בפריט אחד, כמו הוספת מחיצות בתוך רשימה. לא כדאי לאפשר למחיצות לשנות את מדדי הגלילה, כי הן לא צריכות להיחשב כרכיבים עצמאיים. בנוסף, הביצועים לא יושפעו כי הקווים המפרידים קטנים. סביר להניח שהמפריד צריך להיות גלוי כשהפריט שלפניו גלוי, כדי שהוא יוכל להיחשב כחלק מהפריט הקודם:
LazyVerticalGrid( columns = GridCells.Adaptive(100.dp) ) { item { Item(0) } item { Item(1) Divider() } item { Item(2) } // ... }
כדאי להשתמש בסידור מותאם אישית
בדרך כלל, ברשימות 'איט' יש הרבה פריטים והן גדולות יותר מגודל המאגר שאפשר לגלול בו. עם זאת, אם הרשימה כוללת מעט פריטים, תוכלו להגדיר דרישות ספציפיות יותר לגבי המיקום שלהם בחלון התצוגה.
כדי לעשות זאת, אפשר להשתמש בקטגוריה בהתאמה אישית Arrangement
ולהעביר אותה אל LazyColumn
. בדוגמה הבאה, האובייקט TopWithFooter
צריך להטמיע רק את ה-method 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
החל מגרסה 1.2 של Compose, כדי למקסם את הביצועים של הפריסה האיטית, מומלץ להוסיף את הערך contentType
לרשימות או לרשתות. כך אפשר לציין את סוג התוכן של כל פריט בפריסה במקרים שבהם כותבים רשימה או רשת שמורכבת מכמה סוגים של פריטים:
LazyColumn { items(elements, contentType = { it.type }) { // ... } }
כשמציינים את הערך contentType
, אפשר לעשות שימוש חוזר ב-Compose רק בין פריטים מאותו סוג. שימוש חוזר יעיל יותר כשאתם יוצרים פריטים בעלי מבנה דומה, ולכן חשוב לציין את סוגי התוכן כדי לוודא ש-Compose לא ינסה ליצור פריט מסוג א' מעל פריט שונה לגמרי מסוג ב'. כך תוכלו למקסם את היתרונות של שימוש חוזר ברכיבים ולשפר את הביצועים של הפריסה האיטית.
מדידת ביצועים
אפשר למדוד את הביצועים של פריסה עם טעינת פריטים בזמן אמת (Lazy) באופן מהימן רק כשהיא פועלת במצב הפצה ועם אופטימיזציה של R8 מופעלת. ב-builds לניפוי באגים, יכול להיות שהגלילה של פריסה עצלה תהיה איטית יותר. מידע נוסף זמין במאמר ביצועי הרכבת קוד.
מומלץ עבורך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- העברה של
RecyclerView
לרשימת העצלנים - שמירת המצב של ממשק המשתמש בחלונית הכתיבה
- Kotlin ל-Jetpack פיתוח נייטיב