Unicorn Commerce — Coding Bootcamp — The Unicorn Fullstack Professional Developer Guide to Modern Android Development — Part 6
Unicorn Commerce — Modern Android Development Part 6— Jetpack Compose Lazy Layouts — LazyColumn, LazyRow, and LazyGrid
This part continues from where we left off in Part5
Please use the feature/develop_starter_kit_part6 branch to follow along
Alternatively, one may use the starter-kit-part6 release to follow along
In this part, we are going to cover LazyColumn, LazyRow, and LazyGrid
LazyColumn, LazyRow, and LazyGrid composes only that which is visible in the viewport, which increases the Responsiveness and Performance of the app.
LazyRow, like Row, is a horizontal scrollable list.
LazyColumn, like Column, is a vertical scrollable list.
LazyColumns and LazyRows can use itemsIndexed() instead of Items() if index of the item is needed in the list
Index and Item can be used in the lambda expression
Compose provides 2 types of grids — LazyVerticalGrid and LazyHorizontalGrid
Let’s implement the list of tshirts for sale on the Unicorn Commerce app using LazyRow and LazyColumn on the CollectionsScreen.
First, let’s create a ProductCategories.kt file in $PROJECT_ROOT/src/main/app/unicornapp/mobile/android/unicorn/data package
/**
* ProductCategories.kt
*/
val productCategories = listOf<String>(
"Tshirts",
"Men's Apparel",
"Women's Apparel",
"Shoes"
)
Next, we need to create a Product.kt file containing the Product data class in $PROJECT_ROOT/src/main/app/unicornapp/mobile/android/unicorn/data package
/**
* Product.kt
*/
data class Product (
val name: String,
val price: String,
val description: String,
val image: Int
)
val products = listOf<Product>(
Product("Don't Panic", "$29.99", "Don't Panic Tshirt", R.drawable.tshirt_1),
Product("Got Milky Way", "$39.99", "Got Milky Way Tshirt", R.drawable.tshirt_2),
Product("Starry Nights", "$49.99", "Starry Nights Tshirt", R.drawable.tshirt_3),
)
We may now improve the ItemProduct.kt file in $PROJECT_ROOT/src/main/app/unicornapp/mobile/android/unicorn/ui/screens to include the Product data class as below
/**
* ItemProduct.kt
*/
@Composable
fun ItemProduct(
navController: NavController,
product: Product
) {
val context = LocalContext.current
Column(
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.Start,
modifier = Modifier
.fillMaxWidth()
/* TODO-FIXME-CLEANUP .background(Color(0xFF495E57)) */
) {
Text(
modifier = Modifier
.clickable {
navController.navigate(route = Screen.HomeDetailScreen.route)
}
.padding(20.dp),
text = product.name,
fontSize = MaterialTheme.typography.titleLarge.fontSize,
color = Color.White,
fontWeight = FontWeight.Bold,
)
Text(
modifier = Modifier
.clickable {
navController.navigate(route = Screen.HomeDetailScreen.route)
}
.padding(20.dp),
text = product.description,
fontSize = MaterialTheme.typography.titleLarge.fontSize,
color = Color.White,
fontWeight = FontWeight.Bold
)
Row(
Modifier
.fillMaxWidth()
.padding(20.dp), horizontalArrangement = Arrangement.Start) {
Text(
text = product.price,
Modifier.width(200.dp),
fontSize = 14.sp,
color = Color.White,
fontWeight = FontWeight.Light
)
Image(
painter = painterResource(id = product.image),
contentDescription = "",
Modifier
.height(200.dp)
.clip(RoundedCornerShape(20.dp)),
)
}
}
}
@Preview
@Composable
fun ItemProductPreview() {
ItemProduct(
navController = rememberNavController(),
Product("Tshirt", "$29.99", "Tshirt for sale", R.drawable.tshirt_1)
)
}
We may now implment the CollectionsScreen.kt using LazyRow and LazyColumn as below
/**
* CollectionsScreen.kt
*/
@Composable
fun CollectionsScreen(
navController: NavController,
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Image(
painterResource(
id = R.drawable.banner_bg_6),
contentDescription = "",
contentScale = ContentScale.FillBounds,
modifier = Modifier.matchParentSize()
)
Column(
Modifier.padding(
top = 70.dp,
bottom = 50.dp
),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
modifier = Modifier.clickable {
navController.navigate(Screen.HomeScreen.route) {
popUpTo(Screen.HomeScreen.route) {
inclusive = true
}
}
},
text = "Collections",
color = Color.White,
fontSize = MaterialTheme.typography.titleSmall.fontSize,
fontWeight = FontWeight.Bold
)
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.SpaceEvenly
) {
LazyRow {
items(productCategories) { productCategory ->
ItemCategory(category = productCategory)
}
}
Divider(
modifier = Modifier.padding(8.dp),
color = Color.Gray,
thickness = 1.dp
)
LazyColumn {
items(products) {product ->
ItemProduct(
navController = navController,
product = product
)
Divider(
modifier = Modifier.padding(8.dp),
color = Color.Gray,
thickness = 1.dp
)
}
}
}
}
}
}
@Preview
@Composable
fun CollectionsScreenPreview() {
CollectionsScreen(navController = rememberNavController())
}
This gives us the list of product categories in a LazyRow and the list of products in a LazyColumn as below
In addition to our Collections screen, we may create a SpringCollections screen as below
@Composable
fun SpringCollectionsScreen(
navController: NavController
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Image(
painterResource(
id = R.drawable.banner_bg_6),
contentDescription = "",
contentScale = ContentScale.FillBounds,
modifier = Modifier.matchParentSize()
)
Text(
modifier = Modifier.clickable {
navController.navigate(Screen.HomeScreen.route) {
popUpTo(Screen.HomeScreen.route) {
inclusive = true
}
}
},
text = "SpringCollectionScreen",
color = Color.White,
fontSize = MaterialTheme.typography.titleSmall.fontSize,
fontWeight = FontWeight.Bold
)
}
}
@Preview
@Composable
fun SpringCollectionsScreenPreview() {
SpringCollectionsScreen(navController = rememberNavController())
}
We may now implement LazyVerticalGrid in SpringCollectionsScreen as below
@Composable
fun SpringCollectionsScreen(
navController: NavController
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Image(
painterResource(
id = R.drawable.banner_bg_6),
contentDescription = "",
contentScale = ContentScale.FillBounds,
modifier = Modifier.matchParentSize()
)
LazyVerticalGrid(
modifier = Modifier.padding(
top = 90.dp,
bottom = 50.dp
),
columns = GridCells.Adaptive(150.dp)
) {
items(500) { number ->
MyGridCell(number)
}
}
}
}
@Composable
fun MyGridCell(number: Int) {
Card(
modifier = Modifier.padding(8.dp),
elevation = 20.dp
) {
Box(
modifier = Modifier.aspectRatio(1f),
contentAlignment = Alignment.Center
) {
Text(
text = "Item " + number,
fontSize = 20.sp
)
Image(
painter = painterResource(id = R.drawable.tshirt_2),
contentDescription = "",
Modifier
.height(200.dp)
.clip(RoundedCornerShape(20.dp)),
)
}
}
}
@Preview
@Composable
fun SpringCollectionsScreenPreview() {
SpringCollectionsScreen(navController = rememberNavController())
}
This gives us the below layout for the SpringCollections screen
Create a color theme called UnicornAppColor in Color.kt as below
val Purple80 = Color(0xFFD0BCFF)
val PurpleGrey80 = Color(0xFFCCC2DC)
val Pink80 = Color(0xFFEFB8C8)
val Olive100 = Color(0XFF777d68)
val Maroon100 = Color(0xFFB60F46)
val Purple40 = Color(0xFF6650a4)
val PurpleGrey40 = Color(0xFF625b71)
val Transparent = Color(0xFF00000000)
object UnicornApppColor {
val one = Color(0xFFEEE299)
val two = Color(0xFFCDA362)
val three = Color(0xFFAB6B49)
val four = Color(0xFF733E4F)
val five = Color(0xFF402C44)
val graphene = Color(0xFF333333)
}
Modify Theme.kt to use UnicornAppColor theme as follows
private val DarkColorScheme = darkColorScheme(
primary = UnicornApppColor.four,
onPrimary = UnicornApppColor.one,
secondary = UnicornApppColor.five,
onSecondary = UnicornApppColor.two,
tertiary = UnicornApppColor.graphene,
onTertiary = Color.White
)