लिस्ट और ग्रिड

कई ऐप्लिकेशन को आइटम के संग्रह दिखाने की ज़रूरत होती है. इस दस्तावेज़ में बताया गया है कि की मदद से 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 हॉरिज़ॉन्टल तौर पर स्क्रोल करता है स्क्रोलिंग सूची.

Compose में ज़्यादातर लेआउट से लेज़ी कॉम्पोनेंट अलग होते हैं. इसके बजाय कॉन्टेंट ब्लॉक करने के @Composable पैरामीटर को स्वीकार किया जा रहा है, जिससे ऐप्लिकेशन सीधे तौर पर कंपोज़ेबल का इस्तेमाल करते हैं, तो लेज़ी कॉम्पोनेंट एक LazyListScope.() ब्लॉक देते हैं. यह LazyListScope ब्लॉक एक डीएसएल सुविधा देता है, जिसकी मदद से ऐप्लिकेशन, आइटम के कॉन्टेंट के बारे में जानकारी दे सकते हैं. कॉन्टेंट बनाने इसके बाद, लेज़ी कॉम्पोनेंट को हर आइटम के कॉन्टेंट को लेआउट और स्क्रोल पोज़िशन के हिसाब से ज़रूरी है.

LazyListScope डीएसएल

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 कंपोज़ेबल का इस्तेमाल करके ग्रिड में आइटम दिखाए जा सकते हैं. लेज़ी वर्टिकल ग्रिड अपने आइटम को वर्टिकल तौर पर स्क्रोल किए जा सकने वाले कंटेनर में दिखाएगा, जो एक से ज़्यादा कॉलम में वैल्यू होंगी, जबकि लेज़ी हॉरिज़ॉन्टल ग्रिड का व्यवहार एक जैसा होगा आदी है.

ग्रिड में एपीआई की उतनी ही असरदार सुविधाएं होती हैं जैसे कि लिस्ट में होती हैं. साथ ही, वे बहुत मिलता-जुलता डीएसएल - 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 ऐसे कंपोज़ेबल होते हैं जिनकी मदद से आप आइटम के लेज़ी-लोडेड, स्टेज किए गए ग्रिड बना सकते हैं. लेज़ी वर्टिकल स्टेज्ड ग्रिड, अपने आइटम को वर्टिकल तरीके से स्क्रोल करते हुए दिखाता है एक कंटेनर, जो कई कॉलम में फैला होता है और जिसकी सहायता से अलग-अलग आइटम अलग-अलग ऊंचाई पर. लेज़ी हॉरिज़ॉन्टल ग्रिड, अलग-अलग चौड़ाई वाले आइटम वाला हॉरिज़ॉन्टल ऐक्सिस.

यहां दिया गया स्निपेट, 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.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()
)

Compose में इमेज की लेज़ी स्टैग की गई ग्रिड
दूसरी इमेज. तय किए गए कॉलम के साथ लेज़ी स्टेज किए गए वर्टिकल ग्रिड का उदाहरण

कॉन्टेंट पैडिंग

कभी-कभी आपको कॉन्टेंट के किनारों के आस-पास पैडिंग (जगह) जोड़ने की ज़रूरत पड़ सकती है. द लेज़ी कॉम्पोनेंट से आपको यह तय करने में मदद मिलती है कि 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)
    }
}

आइटम कुंजियां

डिफ़ॉल्ट रूप से, हर आइटम की स्थिति को सूची या ग्रिड. हालांकि, अगर डेटा सेट में बदलाव होता है, तो इसकी वजह से समस्याएं हो सकती हैं, क्योंकि स्थिति बदलने के दौरान याद रखी गई कोई भी स्थिति मिटा दी जाती है. अगर आपको लगता है कि LazyColumn में LazyRow की स्थिति, अगर लाइन में आइटम की पोज़िशन बदलती है, तो फिर उपयोगकर्ता पंक्ति में अपनी स्क्रोल करने की जगह खो देगा.

इससे बचने के लिए, हर आइटम को एक यूनीक और स्थायी कुंजी दी जा सकती है. इसके लिए, key पैरामीटर के लिए ब्लॉक. स्थिर कुंजी उपलब्ध कराने से, आइटम की स्थिति डेटा सेट में होने वाले बदलावों के मुताबिक:

LazyColumn {
    items(
        items = messages,
        key = { message ->
            // Return a stable + unique key for the item
            message.id
        }
    ) { message ->
        MessageRow(message)
    }
}

कुंजियां उपलब्ध कराने से, Compose की सुविधा में आपके ऑर्डर का क्रम सही से मैनेज करने में मदद मिलती है. उदाहरण के लिए, अगर आपके आइटम में याद रखी गई स्थिति शामिल है, तो कुंजियों को सेट करने से जब आइटम की स्थिति बदल जाती है, तो इस स्थिति को आइटम के साथ ले जाने के लिए लिखें.

LazyColumn {
    items(books, key = { it.id }) {
        val rememberedValue = remember {
            Random.nextInt()
        }
    }
}

हालांकि, आइटम बटन के तौर पर किस टाइप का इस्तेमाल किया जा सकता है, इसकी एक सीमा तय है. कुंजी के टाइप के साथ काम करना ज़रूरी है Bundle, Android का वह तरीका जो यह जानकारी दिखाता है कि गतिविधि को कब फिर से बनाया गया. Bundle, प्रिमिटिव जैसे टाइप के साथ काम करता है enum या पार्सलेबल.

LazyColumn {
    items(books, key = {
        // primitives, enums, Parcelable, etc.
    }) {
        // ...
    }
}

कुंजी Bundle के साथ काम करनी चाहिए, ताकि rememberSaveable कंपोज़ेबल गतिविधि को फिर से बनाए जाने पर, उसे वापस लाया जा सकता है या इस आइटम से दूर स्क्रोल करके वापस स्क्रोल करें.

LazyColumn {
    items(books, key = { it.id }) {
        val rememberedValue = rememberSaveable {
            Random.nextInt()
        }
    }
}

आइटम पर आधारित ऐनिमेशन

अगर आपने RecyclerView विजेट का इस्तेमाल किया है, तो आपको पता चल जाएगा कि वह आइटम को ऐनिमेट करता है बदलाव अपने-आप हो जाता है. आइटम का क्रम बदलने के लिए, लेज़ी लेआउट में एक जैसी सुविधाएं उपलब्ध होती हैं. यह एपीआई इस्तेमाल में आसान है - आपको सिर्फ़ इसे सेट करना होगा animateItemPlacement आइटम कॉन्टेंट का मॉडिफ़ायर:

LazyColumn {
    items(books, key = { it.id }) {
        Row(Modifier.animateItemPlacement()) {
            // ...
        }
    }
}

ज़रूरत पड़ने पर, कस्टम ऐनिमेशन स्पेसिफ़िकेशन भी दिए जा सकते हैं:

LazyColumn {
    items(books, key = { it.id }) {
        Row(
            Modifier.animateItemPlacement(
                tween(durationMillis = 250)
            )
        ) {
            // ...
        }
    }
}

पक्का करें कि आपने अपने आइटम की कुंजियां दी हों, ताकि नई चीज़ें ढूंढी जा सकें स्थानांतरित तत्व के लिए स्थिति.

क्रम बदलने के अलावा, जोड़ने और हटाने के लिए आइटम ऐनिमेशन फ़िलहाल जिन्हें अभी डेवलप किया जा रहा है. प्रोग्रेस को यहां ट्रैक किया जा सकता है समस्या 150812265 है.

स्टिकी हेडर (प्रयोग के तौर पर उपलब्ध)

ग्रुप किए गए डेटा की सूचियां दिखाते समय 'स्टिकी हेडर' पैटर्न मददगार होता है. नीचे 'संपर्क सूची' का एक उदाहरण दिया गया है, जिसे हर संपर्क की संपर्क सूची के हिसाब से ग्रुप में बांटा गया है नाम का पहला अक्षर:

फ़ोन का वीडियो, जिसमें संपर्क सूची में ऊपर और नीचे की ओर स्क्रोल करते हुए दिखाया गया है

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

स्क्रोल करने की जगह बदलने के लिए प्रतिक्रिया दिख रही है

कई ऐप्लिकेशन को स्क्रोल करने की जगह और आइटम के लेआउट में होने वाले बदलावों पर प्रतिक्रिया देनी होती है और उन्हें सुनना होता है. लेज़ी कॉम्पोनेंट, शिपिंग के लिए इस्तेमाल किए जाने वाले मुख्य कॉम्पोनेंट को, LazyListState:

@Composable
fun MessageList(messages: List<Message>) {
    // Remember our own LazyListState
    val listState = rememberLazyListState()

    // Provide it to LazyColumn
    LazyColumn(state = listState) {
        // ...
    }
}

आसान इस्तेमाल के मामलों में, ऐप्लिकेशन को आम तौर पर सिर्फ़ दिखाई देने वाला पहला आइटम. इसके लिए LazyListState यह firstVisibleItemIndex और firstVisibleItemScrollOffset प्रॉपर्टी.

अगर हम किसी बटन को दिखाने या छिपाने के उदाहरण का इस्तेमाल इस आधार पर करें कि उपयोगकर्ता ने पहले आइटम को स्क्रोल किया है या नहीं, तो:

@OptIn(ExperimentalAnimationApi::class)
@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()
        }
    }
}

कंपोज़िशन में स्थिति को सीधे तौर पर पढ़ना तब फ़ायदेमंद होता है, जब आपको अपडेट करना हो अन्य यूज़र इंटरफ़ेस (यूआई) कंपोज़ेबल. हालांकि, कुछ मामलों में ऐसे भी उदाहरण हो सकते हैं जहां इवेंट की ज़रूरत न हो करने के लिए इस्तेमाल किया जा सकता है. इसका एक सामान्य उदाहरण यह है कि जब उपयोगकर्ता किसी खास पॉइंट से स्क्रोल कर लेता है, तब Analytics इवेंट. मैनेज करने के लिए साथ ही, हम किसी 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 हमारे LazyColumn में items() तक. व्यू में पेजिंग सहायता की तरह ही, डेटा लोड होने के दौरान प्लेसहोल्डर दिखाएं. इसके लिए, यह देखें कि 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
        // ...
    )
}

जब आपको पता चलता है कि डेटा होने के बाद आपके आइटम का अनुमानित साइज़ अपने-आप लोड होने की सुविधा का इस्तेमाल करके, यह पक्का किया जा सकता है कि आपके आइटम का साइज़ लोड करने से पहले और बाद में एक जैसा दिखाना. उदाहरण के लिए, कुछ प्लेसहोल्डर जोड़ना. इससे स्क्रोल करने की सही जगह को बनाए रखने में मदद मिलेगी.

एक ही दिशा में स्क्रोल किए जा सकने वाले कॉम्पोनेंट को नेस्ट करने से बचें

यह सिर्फ़ उन मामलों में लागू होता है जहां पहले से तय नियमों के बिना, स्क्रोल किए जा सकने वाले बच्चों को नेस्ट किया जाता है पैरंट की साइज़ के लिए, जिसे स्क्रोल किया जा सकता है. उदाहरण के लिए, वर्टिकल तौर पर स्क्रोल करने की सुविधा में, तय ऊंचाई के बिना चाइल्ड 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)
    ) {
        // ...
    }
}

एक ही आइटम में कई एलिमेंट को शामिल करने से बचें

इस उदाहरण में, दूसरा आइटम lambda एक ब्लॉक में दो आइटम का उत्सर्जन करता है:

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 ऑब्जेक्ट को सिर्फ़ 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 लॉन्च किया जा रहा है, ताकि लेज़ी की परफ़ॉर्मेंस को बेहतर बनाया जा सके लेआउट, contentType को भी शामिल किया जा सकता है. इससे आपको यह तय करने में मदद मिलती है कि किस तरह का कॉन्टेंट लेआउट का आइटम, उन मामलों में जहां आप सूची या ग्रिड बनाते हैं. आइटम न चुनें:

LazyColumn {
    items(elements, contentType = { it.type }) {
        // ...
    }
}

जब आप contentType लिखने के लिए सिर्फ़ कंपोज़िशन का इस्तेमाल किया जा सकता है डालें. दरअसल, ट्रेंडिंग पेज का दोबारा इस्तेमाल करना ज़्यादा कारगर होता है, मिलते-जुलते स्ट्रक्चर वाले आइटम तैयार करते हैं. साथ ही, कॉन्टेंट के टाइप देना पक्का करता है लिखें सुविधा, पूरी तरह से A प्रकार के आइटम को लिखने का प्रयास नहीं करती है B टाइप के अलग-अलग आइटम हैं. इससे कंपोज़िशन के फ़ायदों को बढ़ाने में मदद मिलती है लेज़ी लेआउट का इस्तेमाल करें.

परफ़ॉर्मेंस को मेज़र करना

लेज़ी लेआउट की परफ़ॉर्मेंस का आकलन सिर्फ़ तब किया जा सकता है, जब और R8 ऑप्टिमाइज़ेशन चालू होना चाहिए. डीबग बिल्ड पर, लेज़ी लेआउट स्क्रोल करने में समय लग सकता है. इस बारे में ज़्यादा जानकारी के लिए, इसे पढ़ें परफ़ॉर्मेंस लिखें.