,

کار با LazyColumn و LazyRow در Compose

LazyColumn و LazyRow در Jetpack Compose: راهنمای کامل با مثال‌های کاربردی
نمایش LazyColumn، LazyRow و LazyGrids در Compose

در مبحث قبلی با FlowRow و FlowColumn آشنا شدیم و گفتیم که این دو کامپوننت برای آیتم های زیاد مناسب نیستند. پس باید چیکار کنیم؟

LazyColumn و LazyRow در اندروید و کامپوز مولتی پلتفرم، به شما این امکان را می‌دهند تا لیست‌های عمودی و افقی ایجاد کنید که فقط آیتم‌های قابل مشاهده را، رندر کنند. این رویکرد (“تنها در زمان نیاز” (just-in-time))، باعث بهبود چشمگیر عملکرد و کاهش مصرف حافظه می‌شود، به‌ویژه هنگام کار با لیست‌های بزرگ یا بی‌نهایت.

این دو کامپوننت شبیه RecyclerView در سیستم View سنتی اندروید، فقط آیتم‌های قابل مشاهده در صفحه را رندر می‌کنند و با اسکرول کاربر، آیتم‌های جدید را به صورت پویا ایجاد می‌کنند.

مفهوم Composable Slot Reuse در LazyColumn – آیتم 3 به عنوان آیتم 10 استفاده مجدد می‌شود

ویژگی‌ها و مزایای کلیدی

کارایی بالا

بزرگترین مزیت LazyColumn و LazyRow، کارایی بالای آن‌هاست. با رندر کردن فقط آیتم‌های قابل مشاهده، این کامپوننت‌ها از مصرف منابع سیستم جلوگیری می‌کنند و تجربه کاربری روان‌تری را فراهم می‌کنند.

در لیست‌های بزرگ (بیش از ۱۰۰ آیتم)، استفاده از LazyColumn یا LazyRow به جای Column یا Row معمولی می‌تواند تفاوت چشمگیری در عملکرد برنامه ایجاد کند.

صرفه‌جویی در حافظه

از آنجایی که فقط آیتم‌های قابل مشاهده رندر می‌شوند، حافظه کمتری مصرف می‌شود. این ویژگی به‌ویژه در دستگاه‌های با منابع محدود یا هنگام نمایش لیست‌های حاوی تصاویر یا محتوای سنگین اهمیت دارد.

کد ساده و خوانا

پیاده‌سازی LazyColumn و LazyRow در Jetpack Compose بسیار ساده‌تر از RecyclerView در سیستم View سنتی است که می‌توانید لیست‌های پیچیده را با کدی کمتر و خواناتر ایجاد کنید.

پشتیبانی از انیمیشن‌ها

LazyColumn و LazyRow به صورت پیش‌فرض از انیمیشن‌های آیتم‌ها پشتیبانی می‌کنند. با استفاده از modifier animateItem می‌توانید انیمیشن‌های جذابی برای افزودن، حذف یا جابجایی آیتم‌ها ایجاد کنید.

پیاده‌سازی LazyColumn با مثال‌ها

مثال ساده LazyColumn

یک مثال ساده از پیاده‌سازی LazyColumn برای نمایش لیستی متن‌ها:

@Composable
fun SimpleLazyColumn() {
    val items = listOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5")
    
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
    ) {
        items(items) { item ->
            Text(
                text = item,
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(vertical = 8.dp)
            )
        }
    }
}

در این مثال:

  • با استفاده از LazyColumn یک لیست عمودی (زیرهم) ایجاد می‌کنیم.
  • با تابع items لیستی از آیتم‌ها را به LazyColumn اضافه می‌کنیم.
  • هر آیتم یک Text است که متن مرتبط را نمایش می‌دهد.

LazyColumn با آیتم‌های پیچیده‌تر

حالا یک مثال پیچیده‌تر با آیتم‌های حاوی تصویر و متن :

@Composable
fun LazyColumnWithImages() {
    val items = listOf(
        ItemData("Item 1", R.drawable.image1),
        ItemData("Item 2", R.drawable.image2),
        ItemData("Item 3", R.drawable.image3),
        ItemData("Item 4", R.drawable.image4),
        ItemData("Item 5", R.drawable.image5)
    )
    
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.spacedBy(12.dp),
    ) {
        items(items, key = { it.id }) { item ->
            Card(
                modifier = Modifier.fillMaxWidth()
            ) {
                Row(
                    modifier = Modifier.padding(16.dp),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Image(
                        painter = painterResource(item.imageRes),
                        ...
                    )
                    Spacer(modifier = Modifier.width(16.dp))
                    Text(
                        text = item.title,...
                    )
                }
            }
        }
    }
}

در این مثال پیشرفته‌تر:

  • از verticalArrangement برای ایجاد فاصله بین آیتم‌ها استفاده شده است.
  • هر آیتم به صورت یک Card طراحی شده که حاوی تصویر و متن است.
  • با استفاده از پارامتر key، یک کلید یکتا برای هر آیتم تعریف شده که به بهینه‌سازی عملکرد کمک می‌کند.

افزودن هدر و فوتر به LazyColumn

برای افزودن هدر و فوتر به LazyColumn می‌توانید از توابع item و items به صورت ترکیبی استفاده کنید:

@Composable
fun LazyColumnWithHeaderFooter() {
    val items = listOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5")
    
    LazyColumn(
        modifier = Modifier.fillMaxSize()
    ) {
        // Header
        item {
            Text(
                text = "Esfandune.ir",
                ...
            )
        }
        
        // Items
         items(categories) { category ->
                    Card(
                        modifier = Modifier.clickable { },
                    ) {
                        Text(
                            text = category,
                            modifier = Modifier.padding(
                                horizontal = 16.dp,
                                vertical = 8.dp
                            ),
                        )
                    }
                }
        
        // Footer
        item {
            Text(
                text = "Footer",
               ...
            )
        }
    }
}

در این مثال، با استفاده از تابع item یک هدر و یک فوتر به LazyColumn اضافه کرده‌ایم. این تابع برای افزودن آیتم‌های تکی استفاده می‌شود، در حالی که تابع items برای افزودن لیستی از آیتم‌ها به کار می‌رود.

پیاده‌سازی LazyRow با مثال‌ها

مثال ساده LazyRow

LazyRow مشابه LazyColumn است اما برای نمایش لیست‌های افقی استفاده می‌شود. در زیر یک مثال ساده آورده شده است:

@Composable
fun SimpleLazyRow() {
    val items = listOf("Item 1", "Item 2", "Item 3", "Item 4", "Item 5")
    
    LazyRow(
        modifier = Modifier.fillMaxWidth(),
        contentPadding = PaddingValues(
            horizontal = 16.dp,
            vertical = 8.dp
        ),
        horizontalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        items(items) { item ->
            Card(
                modifier = Modifier.size(120.dp),
                elevation = 4.dp
            ) {
                Box(
                    contentAlignment = Alignment.Center
                ) {
                    Text(text = item)
                }
            }
        }
    }
}

در این مثال:

  • با استفاده از LazyRow یک لیست افقی ایجاد می‌کنیم.
  • با contentPadding فاصله‌ای از لبه‌های لیست ایجاد می‌کنیم.
  • با horizontalArrangement فاصله بین آیتم‌ها را تنظیم می‌کنیم.

ترکیب LazyColumn و LazyRow

ترکیب LazyColumn و LazyRow

یکی از الگوهای رایج در طراحی رابط کاربری، استفاده از LazyRow درون LazyColumn است. برای مثال، نمایش دسته‌بندی‌ها به صورت افقی در بالای یک لیست عمودی:

@Composable
fun LazyColumnWithLazyRow() {
    val categories = listOf("همه", "محبوب", "جدید", "تخفیف")
    val items = listOf(
        ItemData("Item 1", R.drawable.image1),
        ItemData("Item 2", R.drawable.image2),
        ItemData("Item 3", R.drawable.image3),
        ItemData("Item 4", R.drawable.image4),
        ItemData("Item 5", R.drawable.image5)
    )
    
    LazyColumn(
        modifier = Modifier.fillMaxSize()
    ) {
        // Categories as LazyRow
        item {
            LazyRow(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(vertical = 8.dp),
                contentPadding = PaddingValues(horizontal = 16.dp),
                horizontalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                items(categories) { category ->
                    Card(....) {
                        Text(
                            text = category,
                            ...
                        )
                    }
                }
            }
        }
        
        // Items list
        items(items) { item ->
            Card(
                modifier = Modifier
                    .fillMaxWidth(),
                   ...
            ) {
                Row(
                    modifier = Modifier.padding(16.dp),
                    verticalAlignment = Alignment.CenterVertically
                ) {
                    Image(
                        painter = painterResource(item.imageRes),
                      ...
                    )
                    Spacer(modifier = Modifier.width(16.dp))
                    Text(
                        text = item.title,
                        ...
                    )
                }
            }
        }
    }
}
پیش نمایش کد ترکیب LazyColumn و LazyRow

هشدار

توجه داشته باشید که نمی‌توانید LazyColumn را درون LazyColumn دیگری یا LazyRow را درون LazyRow دیگری قرار دهید، زیرا این کار باعث ایجاد تداخل در اسکرول می‌شود. اما می‌توانید LazyRow را درون LazyColumn یا برعکس قرار دهید.

موارد کاربردی و بهترین روش‌ها

کاربردهای رایج LazyColumn

LazyColumn برای موارد زیر به طور گسترده استفاده می‌شود:

  • لیست پیام‌ها و چت: نمایش لیست مکالمات در اپلیکیشن‌های پیام‌رسان
  • فید خبری و شبکه‌های اجتماعی: نمایش پست‌ها و محتوای کاربران
  • لیست مخاطبین: نمایش لیست مخاطبان در اپلیکیشن‌های تلفن
  • لیست تنظیمات: نمایش گزینه‌های مختلف در بخش تنظیمات برنامه
  • نتایج جستجو: نمایش نتایج جستجو به صورت لیستی

کاربردهای رایج LazyRow

LazyRow معمولاً برای موارد زیر استفاده می‌شود:

  • گالری تصاویر: نمایش مجموعه‌ای از تصاویر به صورت افقی
  • دسته‌بندی‌ها و فیلترها: نمایش گزینه‌های دسته‌بندی یا فیلتر به صورت افقی
  • پیشنهاد محصولات: نمایش محصولات پیشنهادی در فروشگاه‌های آنلاین
  • منوی افقی: ایجاد منوی ناوبری به صورت افقی
  • تب‌ها: نمایش تب‌های قابل اسکرول

بهترین روش‌ها برای بهینه‌سازی

استفاده از کلیدهای یکتا

همیشه برای آیتم‌های LazyColumn و LazyRow از کلیدهای یکتا استفاده کنید. این کار به Compose کمک می‌کند تا آیتم‌ها را به درستی ردیابی کرده و وضعیت آن‌ها را حفظ کند.

items(items, key = { it.id }) { item ->
    // Item content
}

استفاده از Content Type

در صورتیکه آیتم ها در چند شکل مختلف نمایش داده می شوند، با استفاده از contentType مشخص نمایید که هر آیتم از کدام سبک نمایشی هست، تا محاسبات کمتر شود.

items(items, key = { it.id }, contentType = { it.type }) { item -> ...}

بهینه‌سازی حافظه

از توابع remember و rememberSaveable برای جلوگیری از recompose غیرضروری استفاده کنید. این کار به خصوص برای آیتم‌های حاوی تصویر یا محتوای سنگین مهم است.

@Composable
fun ListItem(item: ItemData) {
    val painter = remember { painterResource(item.imageRes) }
    
    Card(...) {
        Image(
            painter = painter,
            contentDescription = null,
            // Other parameters
        )
    }
}

تعیین اندازه ثابت برای آیتم‌ها

هر زمان که ممکن است، اندازه ثابتی برای آیتم‌ها تعیین کنید. این کار به Compose کمک می‌کند تا عملکرد بهتری داشته باشد و محاسبات کمتری برای اندازه‌گیری آیتم‌ها انجام دهد.

اجتناب از عملیات سنگین در آیتم‌ها

از انجام عملیات سنگین مانند پردازش تصویر یا محاسبات پیچیده درون آیتم‌های LazyColumn و LazyRow خودداری کنید. این کار باعث کاهش عملکرد اسکرول می‌شود.

استفاده از Paging 3 برای لیست‌های بزرگ

برای لیست‌های بسیار بزرگ یا بی‌نهایت، از کتابخانه Paging 3 در combination با LazyColumn و LazyRow استفاده کنید. این کتابخانه به شما امکان می‌دهد داده‌ها را به صورت صفحه‌بندی شده بارگذاری کنید.

انیمیشن آیتم‌ها

LazyColumn و LazyRow به صورت پیش‌فرض از انیمیشن‌های آیتم‌ها پشتیبانی می‌کنند. برای فعال‌سازی انیمیشن‌ها، کافی است modifier.animateItem را به محتوای آیتم اضافه کنید تا هنگام حذف یا افزودن آیتمی، با انیمیشن تغییرات اعمال شوند.

LazyColumn {
    // It is important to provide a key to each item
    items(books, key = { it.id }) {
        Row(Modifier.animateItem()) {
            // Item content
        }
    }
}

همچنین می‌توانید انیمیشن‌های سفارشی را با استفاده از پارامتر animationSpec تعریف کنید:

LazyColumn {
    items(books, key = { it.id }) {
        Row(
            modifier = Modifier.animateItem(
                animationSpec = spring(
                    stiffness = Spring.StiffnessMediumLow,
                    dampingRatio = Spring.DampingRatioMediumBouncy
                )
            )
        ) {
            // Item content
        }
    }
}

مدیریت حالت لیست (List State)

با استفاده از LazyListState می‌توانید حالت لیست را کنترل کنید و اطلاعات مربوط به موقعیت اسکرول را ذخیره نمایید:

@Composable
fun LazyColumnWithState() {
    // Create and remember the LazyListState
    val listState = rememberLazyListState()
    
    LazyColumn(state = listState) {
        // Items
    }
    
    // You can use listState to control scroll position
    Button(
        onClick = {
            // Scroll to the top
            coroutineScope.launch {
                listState.animateScrollToItem(0)
            }
        }
    ) {
        Text(text = "Scroll to Top")
    }
}

با استفاده از LazyListState می‌توانید:

  • موقعیت اسکرول فعلی را دریافت کنید.
  • به اولین یا آخرین آیتم اسکرول کنید.
  • به یک آیتم خاص با ایندکس مشخص اسکرول کنید.
  • اطلاعاتی درباره آیتم‌های قابل مشاهده دریافت کنید.

نتیجه‌گیری

LazyColumn و LazyRow از کامپوننت‌های قدرتمند و کارآمد در Jetpack Compose هستند که برای نمایش لیست‌های عمودی و افقی طراحی شده‌اند. با استفاده از این کامپوننت‌ها می‌توانید رابط‌های کاربری کارآمد و روانی ایجاد کنید که به خصوص برای لیست‌های بزرگ یا بی‌نهایت مناسب هستند.

در این مقاله، با مفاهیم پایه LazyColumn و LazyRow، نحوه پیاده‌سازی آن‌ها، کاربردهای عملی و ویژگی‌های پیشرفته آشنا شدیم. با رعایت بهترین روش‌ها و بهینه‌سازی‌های ذکر شده، می‌توانید از حداکثر عملکرد این کامپوننت‌ها بهره‌مند شوید.

Jetpack Compose با ارائه رویکردی مدرن و اعلانی برای ساخت رابط‌های کاربری، توسعه برنامه را ساده‌تر و لذت‌بخش‌تر کرده است. برای کسب اطلاعات کامل تر و بروزتر از این کامپوننت ها، به وبسایت رسمی توسعه دهندگان اندروید مراجعه کنید.

Comments

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *