LazyColumn هي دالة composable في Jetpack Compose لإنشاء قوائم عمودية مع تحميل بطيء للعناصر. على عكس Column، تقوم LazyColumn بإنشاء وتركيب العناصر المرئية فقط على الشاشة، وإعادة استخدامها أثناء التمرير. وفقًا لـ Google Android Documentation, 2025، تعتبر LazyColumn الأداة الرئيسية لعرض مجموعات البيانات الكبيرة في التطبيقات المحمولة بفضل إدارة الذاكرة الفعالة.
الملامح الرئيسية
LazyColumn هي دالة composable تنفذ قائمة عمودية قابلة للتمرير مع تحميل بطيء. على عكس Column الذي يعرض جميع العناصر الفرعية مرة واحدة، تنشئ LazyColumn العناصر الموجودة داخل منطقة العرض فقط.
تعتمد آلية التحميل البطيء في LazyColumn على إعادة استخدام العناصر: عندما يتم إخفاء عنصر أثناء التمرير، يمكن إعادة استخدام تركيبه وتخطيطه لعنصر جديد يظهر. وهذا يوفر الذاكرة ووقت المعالج، خاصة في القوائم الطويلة.
وفقًا لـ Android Developers Blog, 2024، يمكن لـ LazyColumn التعامل بكفاءة مع قوائم تحتوي على عشرات الآلاف من العناصر دون تدهور كبير في الأداء. كل عنصر في LazyColumn لديه مفتاح (key) يساعد Compose في تحديد وحالة العنصر والحفاظ عليها عندما تتغير القائمة.
LazyColumn تقبل المعاملات modifier و state و contentPadding و reverseLayout و verticalArrangement و horizontalAlignment. يتم تعريف المحتوى في كتلة lambda عبر دوال DSL items و item.
@Composable
fun SimpleLazyColumn() {
val itemsList = (1..100).toList()
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(16.dp)
) {
items(itemsList) { item ->
Text(text = "العنصر $item")
}
}
}
توفر كتلة DSL الخاصة بـ LazyColumn الدوال items و item لإضافة المحتوى. تقبل items مجموعة بيانات ومفتاحًا ودالة مصنع لإنشاء العناصر. يضيف item عنصرًا ثابتًا واحدًا إلى القائمة.
itemsIndexed هي نسخة من items تمرر فهرس العنصر بالإضافة إلى البيانات. وهذا مفيد عندما تحتاج إلى معرفة موضع العنصر دون حساب منفصل. items(size) تقبل فقط عدد العناصر ومصنعًا دون الارتباط بمجموعة.
معامل key في items يحدد كل عنصر بشكل فريد. وفقًا لـ Material Design Guidelines, 2025، تعمل المفاتيح على تحسين الأداء عند تحديث العناصر وتحريكها، حيث يمكن لـ Compose تتبع حركة أو تغيير عنصر معين بواسطة مفتاحه.
تسمح دالة items مع contentType لـ LazyColumn بتحسين إعادة استخدام العناصر من أنواع مختلفة. في المثال أدناه، يتم استخدام رؤوس الأقسام والصفوف العادية في قائمة واحدة.
@Composable
fun MixedItemsList() {
LazyColumn {
item {
Text(
text = "رأس",
style = MaterialTheme.typography.headlineMedium
)
}
items(
items = (1..20).toList(),
key = { it },
contentType = { "item" }
) { item ->
Text(text = "الصف $item")
}
}
}
LazyListState هو كائن حالة LazyColumn الذي يتتبع موضع التمرير الحالي وأول عنصر مرئي والإزاحة. يمكن إنشاؤه عبر rememberLazyListState() وتمريره إلى معامل state في LazyColumn.
LazyListState يوفر طريقتي animateScrollToItem و scrollToItem للتمرير البرمجي إلى عنصر معين. تنشئ animateScrollToItem رسمًا متحركًا سلسًا للتمرير، بينما يقوم scrollToItem بالتمرير فوريًا. تتطلب كلتا الطريقتين الاستدعاء داخل coroutine في CompositionContext.
وفقًا لـ Android Developers, 2024، يحتوي LazyListState أيضًا على layoutInfo الذي يوفر معلومات حول العناصر المرئية — فهارسها وإزاحاتها وأحجامها. وهذا مفيد لتنفيذ التحليلات وتتبع المشاهدات أو التمرير اللانهائي.
في هذا المثال، يتم التحكم في LazyColumn عبر LazyListState. يقوم زر بتمرير القائمة إلى العنصر ذي الفهرس 50 برسوم متحركة سلسة.
@Composable
fun ScrollableList() {
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
Column {
Button(
onClick = {
scope.launch {
listState.animateScrollToItem(50)
}
}
) {
Text("تمرير إلى 50")
}
LazyColumn(state = listState) {
items((1..100).toList()) { item ->
Text(
text = "العنصر $item",
modifier = Modifier.padding(8.dp)
)
}
}
}
}
عامل الأداء الرئيسي لـ LazyColumn هو الاستخدام الصحيح للمفاتيح. يجب أن يكون لكل عنصر مفتاح مستقر فريد عبر معامل key. بدون مفاتيح، لا يمكن لـ Compose إعادة استخدام العناصر بشكل صحيح عندما تتغير البيانات، مما يؤدي إلى إعادة التركيب.
contentType يخبر LazyColumn بالعناصر التي لها نفس نوع التخطيط. عندما يدخل عنصران لهما نفس contentType إلى مجموعة إعادة التدوير، يمكن لـ LazyColumn إعادة استخدام تخطيطهما دون إعادة تركيب. وفقًا لـ Android Developers Blog, 2024، يحسن contentType الأداء بنسبة 30–50% في القوائم ذات الأنواع المختلفة من العناصر.
بالنسبة لـ LazyColumn، من المهم أيضًا تجنب المعاملات غير المستقرة في دوال المصنع. في كل مرة يتغير فيها معامل عنصر، يعيد Compose تركيب ذلك العنصر. استخدام remember و derivedStateOf للقيم المستقرة يقلل من عدد عمليات إعادة التركيب.
| العامل | التأثير | التوصية |
|---|---|---|
| المفاتيح (key) | حرج | حدد دائمًا مفتاحًا مستقرًا فريدًا لـ items |
| contentType | كبير | حدد نوع العنصر لتحسين إعادة الاستخدام |
| حجم العناصر | متوسط | استخدم أحجامًا ثابتة حيثما أمكن |
| القوائم المتداخلة | حرج | تجنب LazyColumn داخل LazyColumn — استخدم LazyVerticalGrid |
stickyHeader هي دالة DSL في LazyColumn تثبت رأس القسم في أعلى القائمة أثناء التمرير. عندما يصل القسم التالي إلى الأعلى، يحل محله رأسه. هذا السلوك مألوف للمستخدمين من قوائم جهات الاتصال والتقويمات.
stickyHeader يقبل مفتاحًا ودالة مصنع، على غرار item. على عكس العنصر العادي، يبقى stickyHeader مرئيًا أثناء التمرير عبر محتوى قسمه. عندما يتم تمرير القسم بالكامل، يدفع رأس القسم التالي الرأس السابق للخارج.
وفقًا لـ Material Design Guidelines, 2025، تعمل الرؤوس الثابتة على تحسين التنقل في القوائم الطويلة وتقليل العبء المعرفي على المستخدم. لتطبيق رأس ثابت، ما عليك سوى لف رأس القسم في stickyHeader في الموضع الصحيح بالنسبة لعناصر items.
@Composable
fun SectionedList(sections: Map<String, List<String>>) {
LazyColumn {
sections.forEach { (header, items) ->
stickyHeader {
Text(
text = header,
modifier = Modifier.background(Color.White)
.padding(16.dp)
)
}
items(items) { item ->
Text(text = item, modifier = Modifier.padding(8.dp))
}
}
}
}
الأسئلة الشائعة
Column يعرض جميع العناصر مرة واحدة ومناسب للقوائم التي تحتوي على 20–30 عنصرًا. LazyColumn تنشئ العناصر المرئية فقط وتعيد استخدامها أثناء التمرير، مما يسمح بالعمل مع آلاف العناصر دون فقدان الأداء.
استخدم Arrangement.spacedBy في معامل verticalArrangement أو دوال items مع فاصل عبر الفهرس. للفواصل المعقدة، أضف عنصرًا منفصلاً مع Divider() بين عناصر القائمة.
LazyColumn تعيد التركيب تلقائيًا عندما تتغير مجموعة البيانات، إذا تم استخدام مفاتيح مستقرة. تؤدي تغييرات البيانات المكتشفة عبر mutableStateListOf أو StateFlow إلى إعادة رسم العناصر المتغيرة فقط.
التداخل المباشر لـ LazyColumn داخل LazyColumn غير موصى به — كلاهما لهما تمرير مستقل، مما يخلق تعارضًا في الإيماءات. بدلاً من ذلك، استخدم Column عادي مع LazyColumn داخل Section قابلة للتمرير أو LazyVerticalGrid للشبكات.
استخدم LazyListState.layoutInfo.visibleItemsInfo وقارن فهرس آخر عنصر مرئي مع العدد الإجمالي للعناصر. للتمرير اللانهائي، تتبع عندما يقترب آخر عنصر مرئي من نهاية القائمة.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.