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 کے مطابق کلید کے ساتھ مضامین کی فہرست
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("$totalItems میں سے $firstItem–$lastItem دکھا رہا ہے")
}
پروگراماتی اسکرولنگ listState کے suspend فنکشنز کے ذریعے کی جاتی ہے: scrollToItem(index, scrollOffset) — فوری حرکت (بغیر اینیمیشن)، animateScrollToItem(index) — اینیمیشن کے ساتھ۔ coroutine سے اسکرول کرنے کے لیے، 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 } بتائیں۔ کلید کے بغیر، 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) کلید کی کمی — عناصر کسی بھی فہرست تبدیلی پر دوبارہ مرتب ہوتے ہیں؛ (2) اسنیپ شاٹ فلو کے بغیر mutableStateListOf کا استعمال — تبدیلیاں ٹریک نہیں ہو سکتیں؛ (3) itemContent کے اندر suspend فنکشنز کو کال کرنا — ترکیب میں رکاوٹ ڈالتا ہے؛ (4) مخلوط اقسام کے لیے contentType نہ ہونا — Compose ٹیکسٹ پوسٹس کے لیے اشتہار کی ترکیب دوبارہ استعمال کرتا ہے جس سے بصری نمونے پیدا ہوتے ہیں۔ IT Sectr میں ہم تین یا زیادہ مواد کی اقسام والی تمام فہرستوں میں contentType شامل کرتے ہیں۔
اکثر پوچھے گئے سوالات
تین پیرامیٹرز چیک کریں: (1) key — مستحکم کلید کے بغیر، Compose ترکیب دوبارہ استعمال نہیں کر سکتا، (2) contentType — مختلف عناصر کی اقسام والی فہرستوں کے لیے، (3) beyondBoundsPageCount — تصاویر کے لیے 2 تک بڑھائیں۔ itemContent کے اندر بھاری کمپیوٹیشن کو ڈیٹا کے مطابق کلید کے ساتھ 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() استعمال کریں۔ کلید کے ساتھ فہرست کو اپ ڈیٹ کرتے وقت، Compose خود بخود Modifier.animateItemPlacement() کے ذریعے تبدیلیوں (اضافہ، حذف، دوبارہ ترتیب) کو متحرک کرتا ہے۔
LazyColumn — ایک کالم والی فہرستوں کے لیے (فیڈ، چیٹ، تبصرے)۔ LazyVerticalGrid — گرڈ کے لیے (گیلری، کیٹلاگ، آئیکنز)۔ اگر عناصر فون پر ایک کالم اور ٹیبلیٹ پر دو کالم میں ہونے چاہئیں — GridCells.Adaptive کے ساتھ LazyVerticalGrid استعمال کریں۔ اگر مخلوط گرڈ کی ضرورت ہو (ایک سیکشن میں مختلف کالم نمبر) — LazyColumn استعمال کریں اور items کے اندر افقی LazyRow یا嵌套 کردہ LazyVerticalGrid ڈالیں۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں