LazyColumn — Jetpack Compose का एक घटक जो आलसी लोडिंग के साथ स्क्रॉल करने योग्य सूचियाँ प्रदर्शित करता है। RecyclerView के विपरीत, LazyColumn ViewHolders नहीं बनाता और XML का उपयोग नहीं करता — सभी तत्व composable फ़ंक्शन के माध्यम से घोषणात्मक रूप से वर्णित किए जाते हैं। हम दिखाते हैं कि LazyColumn क्या है, LazyListState और items API कैसे काम करता है, और 60 FPS प्रदर्शन कैसे प्राप्त करें। IT Sectr में हम सभी नए Compose प्रोजेक्ट्स में LazyColumn का उपयोग करते हैं। क्लासिक दृष्टिकोण से तुलना के लिए, RecyclerView के बारे में लेख पढ़ें।
मुख्य बातें
items(), itemsIndexed(), items() फ़ंक्शन।LazyColumn Foundation Compose लाइब्रेरी का एक composable फ़ंक्शन है जो आलसी लोडिंग के साथ तत्वों की एक लंबवत सूची प्रदर्शित करता है: केवल स्क्रीन पर दिखाई देने वाले या पास के तत्व (prefetch ज़ोन) बनाए और रचे जाते हैं। LazyColumn Compose 1.0 (2021) में LazyRow (क्षैतिज सूची) और LazyVerticalGrid (ग्रिड) के साथ दिखाई दिया।
आलसी लोडिंग SubcomposeLayout तंत्र के माध्यम से काम करती है: LazyColumn उपलब्ध स्थान को मापता है, LayoutInfo से दृश्य सीमा का अनुरोध करता है, और केवल उस सीमा में तत्वों की रचना करता है। स्क्रीन से बाहर जाने वाले तत्व रचना छोड़ देते हैं (prefetch बफर को छोड़कर)। Google (Android Performance, 2026) के अनुसार, LazyColumn मध्य-श्रेणी के उपकरणों पर 10000+ तत्वों की सूची में स्क्रॉल करते समय 60 FPS बनाए रखता है।
Column लंबवत स्क्रॉल के साथ — verticalScroll मॉडिफायर लागू करके सभी तत्वों की एक के नीचे एक सामान्य व्यवस्था है। Column आलसी नहीं है: सभी चाइल्ड तत्व तुरंत रचे जाते हैं, भले ही वे दिखाई न दें। 200+ तत्वों की सूची के लिए, Column स्टार्टअप पर महत्वपूर्ण अंतराल का कारण बनता है। LazyColumn केवल दृश्य तत्वों + बफर (डिफ़ॉल्ट रूप से 1 स्क्रीन आगे/पीछे) की रचना करता है, जो इसे लंबी सूचियों के लिए अपरिहार्य बनाता है।
items API LazyColumn के लिए एक्सटेंशन फ़ंक्शन का एक सेट है जो डेटा सूची और प्रत्येक तत्व के लिए DSL विवरणक स्वीकार करता है। मुख्य फ़ंक्शन हैं: निश्चित संख्या के लिए items(count, key, itemContent), सूची के लिए items(list, key, itemContent), इंडेक्स के साथ itemsIndexed(list, key, itemContent)। key पैरामीटर प्रदर्शन के लिए अनिवार्य है — यह Compose को एक स्थिर तत्व पहचानकर्ता देता है।
// itemContent के साथ बुनियादी LazyColumn
@Composable
fun ArticleList(articles: List<Article>) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
// Header — आलसी नहीं, हमेशा शुरुआत में
item {
Text("नवीनतम लेख", style = MaterialTheme.typography.headlineMedium)
}
// id द्वारा key के साथ लेख सूची
items(articles, key = { it.id }) { article ->
ArticleCard(
title = article.title,
summary = article.summary,
onClick = { onArticleClick(article.id) }
)
}
// लोडिंग संकेतक के साथ Footer
item {
CircularProgressIndicator(
modifier = Modifier.fillMaxWidth().padding(16.dp)
)
}
}
}
// कस्टम सूची तत्व
@Composable
fun ArticleCard(title: String, summary: String, onClick: () -> Unit) {
Card(
modifier = Modifier
.fillMaxWidth()
.clickable(onClick = onClick)
) {
Column(modifier = Modifier.padding(12.dp)) {
Text(text = title, style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(4.dp))
Text(text = summary, style = MaterialTheme.typography.bodyMedium)
}
}
}
item {} बनाम items(): एकल तत्वों के लिए item {} का उपयोग करें जो सूची में हमेशा मौजूद रहते हैं (हेडर, फुटर, विभाजक)। गतिशील डेटा सूची के लिए items() का उपयोग करें। items() एक Iterable या Int और एक DSL ब्लॉक स्वीकार करता है जो प्रत्येक तत्व के लिए कॉल किया जाता है। एक LazyColumn में item और items को मिलाएं: कॉल का क्रम प्रदर्शन क्रम निर्धारित करता है।
LazyListState एक ऑब्जेक्ट है जो सूची की स्थिति संग्रहीत करता है: वर्तमान स्क्रॉल स्थिति (firstVisibleItemIndex, firstVisibleItemScrollOffset), दृश्य तत्व (layoutInfo), और प्रोग्रामेटिक स्क्रॉलिंग विधियाँ (scrollToItem, animateScrollToItem)। LazyListState rememberLazyListState() के माध्यम से बनाया जाता है और state पैरामीटर के माध्यम से LazyColumn को पास किया जाता है।
// स्क्रॉल स्थिति संरक्षण के साथ LazyColumn
@Composable
fun ScrollingList(items: List<Item>) {
val listState = rememberLazyListState()
Box(modifier = Modifier.fillMaxSize()) {
LazyColumn(state = listState) {
items(items, key = { it.id }) { item ->
ListItemView(item = item)
}
}
// "ऊपर" बटन 10वें तत्व के बाद दिखाई देता है
val showButton by remember {
derivedStateOf { listState.firstVisibleItemIndex > 10 }
}
AnimatedVisibility(visible = showButton) {
FloatingActionButton(
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(16.dp),
onClick = {
coroutineScope.launch {
listState.animateScrollToItem(0)
}
}
) {
Icon(Icons.Default.KeyboardArrowUp, "ऊपर जाएँ")
}
}
}
}
// दृश्य तत्वों के बारे में जानकारी प्राप्त करना
@Composable
fun ListDebugInfo(listState: LazyListState) {
val visibleItems = listState.layoutInfo.visibleItemsInfo
val totalItems = listState.layoutInfo.totalItemsCount
val firstItem = visibleItems.firstOrNull()?.index
val lastItem = visibleItems.lastOrNull()?.index
Text("$firstItem–$lastItem दिखा रहा है $totalItems में से")
}
प्रोग्रामेटिक स्क्रॉलिंग listState के suspend फ़ंक्शन के माध्यम से की जाती है: scrollToItem(index, scrollOffset) — तत्काल गति (बिना एनिमेशन), animateScrollToItem(index) — एनिमेशन के साथ। कोरूटीन से स्क्रॉल करने के लिए, LaunchedEffect या coroutineScope.launch का उपयोग करें। महत्वपूर्ण: रचना ( @Composable के अंदर) से suspend फ़ंक्शन कॉल न करें — लैम्ब्डा (onClick, LaunchedEffect) का उपयोग करें।
LazyColumn और RecyclerView एक ही समस्या का समाधान करते हैं — लंबी सूचियों का कुशल प्रदर्शन। अंतर आर्किटेक्चर में है: RecyclerView ViewHolder और Adapter (क्लासिक Android View) का उपयोग करता है, LazyColumn XML या ViewHolder के बिना घोषणात्मक composable फ़ंक्शन का उपयोग करता है। चुनाव प्रोजेक्ट के तकनीकी स्टैक पर निर्भर करता है: Compose बनाम View-आधारित UI।
| पैरामीटर | LazyColumn (Compose) | RecyclerView (View) |
|---|---|---|
| लेआउट | Composable फ़ंक्शन (Kotlin DSL) | XML फ़ाइलें + ViewBinding |
| एडॉप्टर | items() / itemsIndexed() DSL | RecyclerView.Adapter + ViewHolder |
| सॉर्टिंग/फ़िल्टरिंग | Snapshot state + derivedStateOf | DiffUtil + AsyncListDiffer |
| एनिमेशन | AnimatedVisibility + Modifier.animateItem | DefaultItemAnimator |
| विभिन्न तत्व प्रकार | item {}/items() + प्रकार के अनुसार when | getItemViewType + एकाधिक ViewHolders |
| स्थिति पर स्क्रॉल | listState.animateScrollToItem() | layoutManager.scrollToPosition() |
| Prefetch | इन-प्रोसेस (SubcomposeLayout बफर) | RecycledViewPool + GapWorker |
| नेटवर्क/पेजिनेशन | collectAsLazyPagingItems() + Paging 3 | PagingDataAdapter + Paging 3 |
Google की अनुशंसा (Android Developers, 2026): Jetpack Compose पर नए प्रोजेक्ट के लिए, LazyColumn का उपयोग करें। View-आधारित प्रोजेक्ट के लिए, RecyclerView का उपयोग करें। LazyColumn को Compose की आवश्यकता है, जो APK में लगभग 3–5 MB जोड़ता है — पुराने उपकरणों का समर्थन करते समय इसे ध्यान में रखें। यदि कोई प्रोजेक्ट पहले से View सिस्टम का उपयोग करता है, तो LazyColumn AndroidView के बिना एक स्क्रीन में XML लेआउट के साथ सह-अस्तित्व में नहीं रह सकता — ऐसे मामलों में, RecyclerView के साथ रहना आसान है।
LazyVerticalGrid निश्चित स्तंभों वाले ग्रिड के लिए LazyColumn का एक संस्करण है। LazyHorizontalGrid निश्चित पंक्तियों वाला एक क्षैतिज ग्रिड है। दोनों घटक LazyColumn के समान आलसी लोडिंग सिद्धांतों और समान items API का उपयोग करते हैं। columns पैरामीटर GridCells.Fixed(N) या GridCells.Adaptive(minSize) के माध्यम से स्तंभों की संख्या निर्धारित करता है।
// अनुकूली स्तंभों के साथ ग्रिड
@Composable
fun PhotoGrid(photos: List<Photo>) {
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 128.dp),
contentPadding = PaddingValues(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(photos, key = { it.id }) { photo ->
AsyncImage(
model = photo.url,
contentDescription = photo.title,
modifier = Modifier.aspectRatio(1f)
)
}
}
}
// क्षैतिज सूची (LazyRow)
@Composable
fun CategoryCarousel(categories: List<Category>) {
LazyRow(
contentPadding = PaddingValues(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp)
) {
items(categories, key = { it.id }) { category ->
FilterChip(
selected = category.isSelected,
onClick = { onCategoryClick(category.id) },
label = { Text(category.name) }
)
}
}
}
GridCells.Adaptive न्यूनतम सेल आकार के आधार पर स्वचालित रूप से स्तंभों की संख्या की गणना करता है। उदाहरण के लिए, GridCells.Adaptive(128.dp) 360 dp चौड़ी स्क्रीन पर 2 कॉलम रखता है, 600 dp टैबलेट पर — 4 कॉलम। GridCells.Fixed(2) हमेशा ठीक 2 कॉलम दिखाता है। Adaptive मल्टी-स्क्रीन अनुकूलन के लिए बेहतर है — यह मीडिया क्वेरी के बिना स्वचालित रूप से स्क्रीन चौड़ाई में समायोजित हो जाता है।
LazyColumn का प्रदर्शन तीन कारकों पर निर्भर करता है: कुंजी स्थिरता (key), सामग्री प्रकार (contentType), और prefetch बफर (beyondBounds)। डिफ़ॉल्ट रूप से, LazyColumn 1 स्क्रीन आगे और 1 पीछे बफर करता है। Google (Android Developers, 2026) विभिन्न तत्व प्रकारों या जटिल रचना वाली सूचियों के लिए इन मापदंडों को कॉन्फ़िगर करने की अनुशंसा करता है।
| पैरामीटर | विवरण | अनुशंसा |
|---|---|---|
| key | स्थिर तत्व पहचानकर्ता | हमेशा key = { it.id } निर्दिष्ट करें। key के बिना, Compose इंडेक्स का उपयोग करता है, और तत्व पुनर्क्रमण एनिमेशन को तोड़ देता है। |
| contentType | पूल पृथक्करण के लिए सामग्री प्रकार | विभिन्न तत्व प्रकारों (टेक्स्ट + इमेज + विज्ञापन) वाली सूचियों के लिए निर्दिष्ट करें। Compose केवल एक ही contentType के भीतर रचना का पुनः उपयोग करेगा। |
| beyondBounds | prefetch स्क्रीन की संख्या | भारी इमेज वाली सूचियों के लिए 2–3 तक बढ़ाएँ। डिफ़ॉल्ट 1 स्क्रीन है। |
| Modifier.animateItem | स्थिति परिवर्तन एनिमेशन | एनिमेटेड सॉर्टिंग और फ़िल्टरिंग के लिए उपयोग करें (Compose 1.7+). |
// contentType और prefetch के साथ अनुकूलित LazyColumn
@Composable
fun OptimizedFeed(items: List<FeedItem>) {
val listState = rememberLazyListState()
LazyColumn(
state = listState,
modifier = Modifier.fillMaxSize(),
beyondBoundsPageCount = 2 // 2 स्क्रीन का prefetch
) {
items(
items = items,
key = { it.id },
contentType = { it.type } // प्रकार के अनुसार विभाजन
) { item ->
when (item) {
is FeedItem.Post -> PostView(item)
is FeedItem.Ad -> AdView(item)
is FeedItem.Suggested -> SuggestedView(item)
}
}
}
}
// listState के माध्यम से प्रदर्शन माप
@Composable
fun ScrollPerformance(listState: LazyListState) {
val scrollInfo = listState.layoutInfo
val visibleCount = scrollInfo.visibleItemsInfo.size
val total = scrollInfo.totalItemsCount
// derivedStateOf — यदि मान नहीं बदला है तो पुनः रचना नहीं करता
val scrollProgress by remember {
derivedStateOf {
if (total > 0) visibleCount.toFloat() / total else 0f
}
}
LinearProgressIndicator(
progress = scrollProgress,
modifier = Modifier.fillMaxWidth().height(2.dp)
)
}
सामान्य गलतियाँ: (1) key की कमी — किसी भी सूची परिवर्तन पर तत्व पुनः रचित होते हैं; (2) स्नैपशॉट फ्लो के बिना mutableStateListOf का उपयोग — परिवर्तन ट्रैक नहीं हो सकते; (3) itemContent के अंदर suspend फ़ंक्शन कॉल करना — रचना को बाधित करता है; (4) मिश्रित प्रकारों के लिए contentType नहीं — Compose टेक्स्ट पोस्ट के लिए विज्ञापन रचना का पुनः उपयोग करता है, जिससे दृश्य कलाकृतियाँ होती हैं। IT Sectr में हम तीन या अधिक सामग्री प्रकारों वाली सभी सूचियों में contentType जोड़ते हैं।
अक्सर पूछे जाने वाले प्रश्न
तीन मापदंडों की जाँच करें: (1) key — स्थिर कुंजी के बिना, Compose रचना का पुनः उपयोग नहीं कर सकता, (2) contentType — विभिन्न तत्व प्रकारों वाली सूचियों के लिए, (3) beyondBoundsPageCount — इमेज के लिए 2 तक बढ़ाएँ। itemContent के अंदर भारी गणनाओं को डेटा द्वारा key के साथ remember में ले जाएँ। सरल ग्राफिक्स के लिए Image के बजाय Modifier.drawWithContent का उपयोग करें।
तत्वों के बीच स्थान के लिए LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) का उपयोग करें। रेखा के साथ दृश्य विभाजक के लिए, items के बीच item { Divider() } जोड़ें। स्वचालित विभाजक: items(items, key = { it.id }) { item -> ... }, और प्रत्येक तत्व के बीच item { HorizontalDivider() } डालें। इसके लिए, LazyListScope.items(list, key) { /* तत्व */ } और अलग से LazyListScope.item { Divider() } का उपयोग करें।
LazyColumn की डिफ़ॉल्ट रूप से अनंत ऊँचाई (fillMaxSize) होती है। निश्चित ऊँचाई के बिना Column के अंदर, LazyColumn अपना आकार निर्धारित नहीं कर सकता। समाधान: (1) LazyColumn पर एक निश्चित ऊँचाई सेट करें: Modifier.height(400.dp), (2) Column के अंदर Modifier.weight(1f) का उपयोग करें, (3) LazyColumn को लंबवत स्क्रॉल करने योग्य कंटेनर के अंदर नेस्ट न करें — हेडर और फुटर के लिए item {} के साथ LazyColumn को रूट तत्व के रूप में उपयोग करें।
LazyColumn स्वचालित रूप से State परिवर्तनों पर प्रतिक्रिया करता है। यदि डेटा mutableStateListOf या mutableStateOf में संग्रहीत है, तो Compose केवल बदले हुए तत्वों को पुनः रचित करता है। ViewModel से सूचियों के लिए, Flow के साथ collectAsState() का उपयोग करें। key के साथ सूची अपडेट करते समय, Compose स्वचालित रूप से Modifier.animateItemPlacement() के माध्यम से परिवर्तनों (जोड़, हटाना, पुनर्क्रमण) को एनिमेट करता है।
LazyColumn — एकल-स्तंभ सूचियों के लिए (फ़ीड, चैट, टिप्पणियाँ)। LazyVerticalGrid — ग्रिड के लिए (गैलरी, कैटलॉग, आइकन)। यदि तत्व फ़ोन पर एक कॉलम और टैबलेट पर दो कॉलम में होने चाहिए — GridCells.Adaptive के साथ LazyVerticalGrid का उपयोग करें। यदि मिश्रित ग्रिड की आवश्यकता है (एक सेक्शन में अलग-अलग कॉलम गणना) — LazyColumn का उपयोग करें और items के अंदर क्षैतिज LazyRow या नेस्टेड LazyVerticalGrid डालें।
सारांश
हम एक मोबाइल एप्लिकेशन टर्नकी विकसित करेंगे
IT Sectr 2017 से स्टार्टअप और व्यवसायों के लिए iOS और Android एप्लिकेशन बनाता है। हम आपको सलाह देंगे और सर्वोत्तम समाधान प्रस्तावित करेंगे।
यह भी पढ़ें