A layout can be defined as the structure of a user interface in an application, either an Activity or a Fragment. This is usually made up of a hierachy of Composables. Jetpack Compose provides several Composables that you can use to build layouts. We will discuss the Row, Column, Box and Scaffold Composables in this course.
Let us get started with the Column and Row Composables.
The Column and Row Composables are used to arrange other Composables in a vertical and horizontal manner respectively. They are usually used to build simple layouts.
The Column Composable has one mandatory argument and three optional arguments. The mandatory argument is named content and requires a @Composable () -> Unit object. This argument is used to specify the children of the layout Composable.
One optional argument is named verticalArrangement and requires a Arrangement.Vertical object. This argument is used to specify the vertical arrangement of the Composable. The default value is Arrangement.Top.
Another optional argument is named horizontalAlignment and requires a Alignment.Horizontal object. This argument is used to specify the horizontal alignment of the Composable. The default value is Alignment.Start.
Lastly, The other argument is named modifier and requires a Modifier object. This argument is used to modify the layout of the Composable.
The Row Composable has one mandatory argument and three optional arguments. The mandatory argument is named content and requires a @Composable () -> Unit object. This argument is used to specify the children of the layout Composable.
The optional arguments are named horizontalArrangement, verticalAlignment and content and require a Arrangement.Horizontal, Alignment.Vertical and a lambda that returns Unit respectively. These arguments are used to specify the horizontal arrangement, vertical alignment and the Composables that will be arranged horizontally respectively.
Adding a Column Composable
Let us add a new package named components to the com.kodeco.android.ui package. This package will contain all the reusable Composables that we will use to build our layouts.
Add a new file named FoodCategoryItem.kt, this file will have a Composable that will display individual food categories. Each category will accept an image and a name as parameters to the Composable.
@Composable
fun FoodCategoryItem(
@DrawableRes icon: Int,
category: String
){
}
We can add a Column Composable to the FoodCategoryItem Composable. The Column Composable will have an Image Composable and a Text Composable as its children.
@Composable
fun FoodCategoryItem(){
@DrawableRes icon: Int,
category: String
}{
Column(
modifier = Modifier.size(75.dp),
horizontalAlignment = Alignment.CenterHorizontally,
){
Image(
modifier = Modifier.size(75.dp),
painter = painterResource(id = icon),
contentDescription = null,
)
Text(
modifier = Modifier.padding(top = 5.dp),
text = category,
textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.bodyMedium
)
}
}
Adding a Row Composable
Add a new file named ProfileBar.kt, this file will have a Composable that will display a profile bar. The bar will contain two images and a text Composable.
@Composable
fun ProfileBar(){
}
Add a Row Composable to the ProfileBar Composable. The Row Composable will have two Image Composables and a Text Composable as its children.
@Composable
fun ProfileBar(){
Row(
modifier = Modifier.fillMaxWidth()
.padding(16.dp),
){
Image(
modifier = Modifier.size(50.dp),
painter = painterResource(id = R.drawable.ic_profile),
contentDescription = null,
)
Text(
text = "Hello, Kodeco",
style = MaterialTheme.typography.bodyLarge,
)
Image(
modifier = Modifier.size(50.dp),
painter = painterResource(id = R.drawable.ic_notifications),
contentDescription = null,
)
}
}
Box and Scaffold Composables
Sometimes, we do not need to arrange Composables in a vertical or horizontal manner. We just need to stack them on top of each other. This is where the Box Composable comes in. The Box Composable is used to stack Composables on top of each other.
A Box Composable has one mandatory argument and three optional arguments. The mandatory argument is named modifier and requires a Modifier object. This argument is used to modify the layout of the Composable.
-
The
contentAlignmentis an optional argument that requires aAlignmentobject. This argument is used to specify the alignment of the Composable. The default value isAlignment.TopStart. -
The
contentargument is a lambda that returnsUnit. This argument is used to specify the Composables that will be stacked on top of each other. -
The
propagateMinConstraintsargument is a boolean that specifies whether the minimum constraints of the Composable should be propagated to its children. The default value isfalse.
The Scaffold Composable is used to build screens that have a top app bar, a bottom navigation bar and a floating action button. It is usually used to build screens that have a Material Design look and feel.
With the Scaffold, you can even specify a color scheme for the container and the content in the layout.
The Scaffold Composable has the first argument being the Modifier. This argument is used to modify the layout of the Composable.
All the different slots in the UI of the Scaffold are provided as arguments.
-
The
topBarargument is used to specify the Composable that will be displayed in the top app bar slot. -
The
bottomBarargument is used to specify the Composable that will be displayed in the bottom navigation bar slot. -
The
floatingActionButtonargument is used to specify the Composable that will be displayed in the floating action button slot. -
The
floatingActionButtonPositionargument is used to specify the position of the floating action button. The default value isFloatingActionButtonPosition.End. -
The
contentargument is a lambda that returnsUnit. This argument is used to specify the Composables that will be displayed in the content slot.
Adding a Box Composable
We can modify the ProfileBar Composable to hold the trailing image in a specific shape and size.
@Composable
fun ProfileBar(){
Row(
modifier = Modifier.fillMaxWidth()
.padding(16.dp),
){
Image(
modifier = Modifier.size(50.dp),
painter = painterResource(id = R.drawable.ic_profile),
contentDescription = null,
)
Text(
text = "Hello, Kodeco",
style = MaterialTheme.typography.bodyLarge,
)
Box(
modifier = Modifier
.background(color = Color.White, shape = CircleShape)
.size(50.dp)
.clip(CircleShape),
contentAlignment = Alignment.Center,
){
Image(
painter = painterResource(id = R.drawable.ic_notifications),
contentDescription = null,
)
}
}
}
Adding a Scaffold Composable
We can start by creating a new package named screens in the com.kodeco.android.ui package. This package will contain all the screens / pages of the app.
Let us now create a new file named HomeScreen.kt in the com.kodeco.android.ui package. This file will have a Composable that will display the home screen of the app.
@Composable
fun HomeScreen(){
}
In this Composable, you can add a Scaffold Composable. The Scaffold Composable will have a Column Composable as its content.
The topAppBar argument of the Scaffold Composable will have a ProfileBar Composable as its value.
@Composable
fun HomeScreen(){
Scaffold(
topBar = {
ProfileBar()
}
){
}
}
The bottomBar argument of the Scaffold Composable will have a Text Composable as its value for now.
We will also add a Column Composable to the Scaffold Composable. The Column Composable will have a Text Composable as its child.
@Composable
fun HomeScreen(){
Scaffold(
topBar = {
ProfileBar()
},
bottomBar = {
Text(text = "Bottom Bar")
}
){
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
){
Text(text = "Home Screen")
}
}
}
Since Scaffold comes from the Material3 library, we will need to annotate the HomeScreen Composable with @OptIn(ExperimentalMaterial3Api::class).
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun HomeScreen(){
Scaffold(
topBar = {
ProfileBar()
},
bottomBar = {
Text(text = "Bottom Bar")
}
){
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
){
Text(text = "Home Screen")
}
}
}
Conclusion
We have been able to see how different layout Composables can be used to place items on the screen. We covered the Column, Row, Box and Scaffold Composables. We will explore more about layout Composables in proceeding sessions.
In our next episode, we will look at how we can leverage the power of Modifier objects to customize the look and feel of Composables.