Preface
In this chapter, we will learn about Jetpack Compose, a modern toolkit for building native UIs.
With this complete tutorial, we will learn how to use Text, TextField, Preview, Column, Row, Button, Card, AlertDialog, MaterialDesign elements, and more. So, without further ado, let's start creating a Jetpack Compose project. Therefore, this chapter is about learning Jetpack Compose for Android with examples.
Notice:To use Jetpack Compose, you need to have the latest Canary version of Android Studio 4.2. Therefore, you can go to the Android Studio preview page and download the latest Canary version and create an Empty Compose Activity.
Compositionable functions
In Jetpack Compose, combinable functions are used to programmatically define all UIs of an application. Therefore, you do not need to use any XML files for the layout of your application. All you need to do to make a composable function is to use the comments of the @Composable function name. The basic syntax of a composable function is:
@Composable fun AnyUiComponent() { // Code for UI element }
Now you know what a composable function is and how to create a composable function using the @Composable annotation. Let's continue to look at the Text example.
Show simple text
In this part of this chapter, we will learn how to use compose to display simple text.
To display text, we use Text Composable and pass the string to display there. For example,
@Composable fun SimpleText(displayText: String) { Text(text = displayText) }
Here, SimpleText is a composable function, inside which we are using Text and passing displayText to it.
You can now call this SimpleText function from the block of the active method. setContentonCreate
class SimpleTextActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { (savedInstanceState) setContent { Column( modifier = (), verticalArrangement = , horizontalAlignment = , ) { SimpleText(getString("I am learning Compose")) } } } }
Here we use a Column for vertically displaying something, and we are calling the SimpleTextComposable function.
Apply styles to text
We can apply various styles to text, such as increasing font size, changing color, etc.
So let's create a function called SetTextStyling:
@Composable fun SetTextStyling(displayText: String, style: TextStyle? = null, maxLines: Int? = null) { Text( text = displayText, modifier = (), style = style ?: , overflow = , maxLines = maxLines ?: Int.MAX_VALUE ) }
In the above function, the parameters are displayText, that is, the text to be displayed, style, that is, the style to be placed on Text, and maxLines is the maximum number of lines allowed by the text. If the text exceeds the maximum line, an ellipsis (...) will be displayed.
We will call this function by passing these parameters. Let's take a look at some of them:
- Set the font size:
style = TextStyle( fontSize = )
- To set the font thickness, pass text-style as:
fontWeight =
Similarly, you can change the font size, text color, font series, underline text, and more. You can see all of this in our open source projects.
Use TextField for input
Just like EditText, in Compose we can use TextField and BaseTextField. BaseTextField is still in the trial stage and can be deleted or added permanently at any time. So to use BaseTextField you need to add the @ExperimentalFoundationApi annotation.
Here is a simple example BaseTextField:
@ExperimentalFoundationApi @Composable fun SimpleTextFieldComponent() { Surface(color = , modifier = ()) { var text by remember { mutableStateOf(TextFieldValue("Enter text here")) } BaseTextField( value = text, modifier = ().fillMaxWidth(), onValueChange = { text = it } ) } }
In the above function we have a BaseTextFieldinside a Surface. We have a callback called onValueChange. This callback is called when some change occurs in the input of , BaseTextField and the updated text will appear as a parameter to the callback.
Here is an example BaseTextField. Material Design also provides EditText with a Composable, namely TextField. A simple implementation of TextField is as follows:
@Composable fun SimpleMaterialTextFieldComponent() { var text by savedInstanceState { "" } TextField( value = text, modifier = ().fillMaxWidth(), onValueChange = { text = it }, label = { Text("Label") } ) }
TextField behaves similarly to BaseTextField. Here TextField, you have one more thing, namely label. A label is a text that is displayed in TextField when there is no text in a TextField.
We can customize this BaseTextField and TextField by passing various parameters to it. For example,
- Show only the numeric keypad:
var text by remember { mutableStateOf(TextFieldValue("0123")) } BaseTextField(value = text, keyboardType = , onValueChange = { text = it } )
- Take the password as input:
keyboardType = , visualTransformation = PasswordVisualTransformation()
- Add placeholder in TextField (displayed when TextField is empty and has focus)
placeholder = { Text("MindOrks") }
Similarly, we can add icons, display error messages in TextFiled, and set errorColor, backgroundColor, intractionState, activeColor, inactiveColor, etc. You can find these in our open source project.
You can try these and view the output in Android Studio itself. Yes, you heard it right. You can preview any UI element in Android Studio itself. Let's see how.
Preview in Android Studio
Android Studio provides a great feature to preview your UI components in the studio itself, and it's very dynamic. So whenever you want to test some UI components, you can simply preview it in Android Studio by making a Composable function and using the @Preview annotation.
Here are the same examples:
// This is a Composable function to display a Text @Composable fun SimpleText(displayText: String) { Text(text = displayText) } @Preview @Composable fun SimpleTextPreview() { SimpleText("Hi I am learning Compose") }
Now, in the Preview tab (to the right of Studio), you can see a preview of the above Composable function.
You can use any number of previews of different widths and heights. If you click on any UI element in the preview, Android Studio takes you to the line that created the UI.
Additionally, you can use the parameters to put some names into the preview name. To name the preview, you need to add the following code:
@Preview(name = "Named Preview")
By default, the preview name is the name of the function.
Note: You cannot pass any arguments to the Preview Composable function.
Preview parameters
In the previous section, we learned how to use the preview feature of Android Studio. Now, when we make any Android application, in most cases the data comes from the server, we populate this data into our application. So the next question is how to preview the data from the server's UI, i.e., its data is now unavailable. For these cases, we can use the @PreviewParameter annotation.
The main idea is to make a virtual data and pass that virtual data to a preview composable function. Since you can't pass any parameters to the Preview Composable Function, in order to achieve this, you need to pass the parameters using the @PreviewParamter annotation.
So, let's first create a virtual data class.
Create a data class named and add the following code to it:
data class Blog( val name: String, val author: String )
Now, create a class named DummyBlogProvider, which implements an interface named PreviewParameterProvider:
class DummyBlogProvider : PreviewParameterProvider<Blog> { override val values = sequenceOf(Blog("Learning Compose", "MindOrks"), Blog("Learning Android", "MindOrks")) override val count: Int = () }
Now that we have finished the virtual data, we can use this virtual data in the preview. Here are the same examples:
@Preview @Composable fun BlogInfo(@PreviewParameter(DummyBlogProvider::class) blog: Blog) { SimpleTextComponent("${} by ${}") }
You can use virtual data to view previews of the UI.
Column
AColumn is a composable layout for placing all its children vertically one after another. It is similar to LinearLayout with a vertical orientation.
Here is an example of the column:
@Composable fun SimpleColumnComponent() { Column(modifier = ()) { Text(text = "Hello! I am Text 1", color = ) Text(text = "Hello! I am Text 2", color = ) } }
Scrollable Column
When you use simpleColumn, you can only use the height of your phone's screen. However, if your content is out of the screen, you can use ScrollableColumn. ScrollableColumn is like a ScrollView.
Here are the same examples:
@Composable fun ScrollableColumnComponent(blogList: List<Blog>) { ScrollableColumn { val context = Column { for (blog in blogList) { Card( shape = RoundedCornerShape(), modifier = ().padding().clickable(onClick = { (context, "Author: ${}", Toast.LENGTH_SHORT).show() }), backgroundColor = Color(()) ) { Text( , style = TextStyle( fontSize = , textAlign = ), modifier = () ) } } } } }
Lazy Column
ScrollableColumn loads all its elements at the beginning. For example, if you have 50 elements and the screen can only show 10 elements at any point in time, and you need to scroll to see another element, then if you are using a ScrollableColumn, all elements will be loaded initially.
However, if you are using LazyColumnFor, it will only load those elements currently visible on the mobile screen. It behaves a bit like a RecyclerView.
Here are the same examples:
@Composable fun LazyColumnScrollableComponent(blogList: List<Blog>) { LazyColumnFor(items = blogList, modifier = ()) { blog -> val context = Card( shape = RoundedCornerShape(), modifier = ().padding().clickable(onClick = { (context, "Author: ${}", Toast.LENGTH_SHORT).show() }), backgroundColor = Color(()) ) { Text( , style = TextStyle( fontSize = , textAlign = ), modifier = () ) } } }
Now, if you want to display content horizontally, you can use Row, ScrollableRow, or Lazy Row. All of these work similarly to Column, ScrollableColumn and Lazy Column, respectively. Therefore, in order to make this blog provide more information, we do not include this section. However, you can find these codes from our open source project.
Box
Box is a composable layout for placing children relative to its edges. Initially, Stack was used instead of Box. But now, Stack is not recommended and Box is introduced.
As the name implies, the child is placed inside the parents. Children in the box are drawn in the specified order, and if the child elements are smaller than the parent, they are placed in the box by default according to alignment.
Here is an example of Box:
@Composable fun SimpleBoxComponent() { Box(modifier = ().padding()) { Image(imageResource(.mindorks_cover)) Text( modifier = (start = , top = ), text = "I am a text over Image", fontSize = , color = ) } }
Button
Button is used to perform certain actions when the user clicks.
Here is an example of a simple Button:
@Composable fun SimpleButtonComponent() { val context = Button( onClick = { (context, "Thanks for clicking!", Toast.LENGTH_LONG).show() }, modifier = ().fillMaxWidth() ) { Text("Click Me") } }
Here, Text is used to place some text on the button, and the onClick callback is used to listen for the button's click event.
By passing various parameters to Button, you can customize them to a large extent. Some of them are:
- Make a rounded corner Button:
shape = RoundedCornerShape()
- Make a Button with borders:
border = BorderStroke(width = , brush = SolidColor())
Similarly, you can add some icons to the button, apply colors to the button, disable the button, make outline buttons, make IconButtons, make FABs, and more. You can check out our open source project for more examples.
Card
Card is a composable layout for making CardViews.
Here are the same examples:
@Composable fun SimpleCardComponent() { Card( backgroundColor = Color(()), modifier = ().fillMaxWidth() ) { Text( text = "Simple Card", textAlign = , style = TextStyle( fontSize = ), modifier = () ) } }
Clickable
You can use Clickable to make composable reactions to users. Clickable supports single click, double click and long press.
Here are the same examples:
@Composable fun SimpleTextComponent() { val context = Text( text = "Click Me", textAlign = , color = , modifier = ().fillMaxWidth().clickable(onClick = { (context, "Thanks for clicking! I am Text", Toast.LENGTH_SHORT).show() }, onLongClick = { (context, "Thanks for LONG click! I am Text", Toast.LENGTH_SHORT).show() }, onDoubleClick = { (context, "Thanks for DOUBLE click! I am Text", Toast.LENGTH_SHORT).show() }) ) }
Likewise, you can make the card clickable.
Image
To display images, we can use Image to composable.
@Composable fun SimpleImageComponent() { // Image is a composable that is used to display some image. val image = imageResource(.mindorks_cover) Column( modifier = () ) { Image(image) } }
You can also make rounded corner images using the following code:
Image( image, modifier = ().clip(shape = RoundedCornerShape()), contentScale = )
Alert Dialog
As the name suggests, AlertDialog is used to display some important messages (and there may be some actions) to the user in the form of a dialog box.
We have titles, text, confirm buttons and close buttons in AlertDialog.
@Composable fun AlertDialogComponent() { val openDialog = remember { mutableStateOf(true) } if () { AlertDialog( onDismissRequest = { = false }, title = { Text(text = "Alert Dialog") }, text = { Text("Hello! I am an Alert Dialog") }, confirmButton = { TextButton( onClick = { = false /* Do some other action */ } ) { Text("Confirm") } }, dismissButton = { TextButton( onClick = { = false /* Do some other action */ } ) { Text("Dismiss") } }, backgroundColor = , contentColor = ) } }
Material AppBar
To display AppBar in Android apps, you can use TopAppBar or BottomAppBar to combine in the app. Here you can have the title (usually the application name), some navigation icons, and some actions on the AppBar.
@Composable fun TopAppBarComponent() { TopAppBar( modifier = ().fillMaxWidth(), title = { Text("App Name") }, navigationIcon = { IconButton(onClick = { /* doSomething() */ }) { Icon() } }, actions = { IconButton(onClick = { /* doSomething() */ }) { Icon() } IconButton(onClick = { /* doSomething() */ }) { Icon() } } ) }
Similarly, we can use BottomAppBar as well.
Material BottomNavigation
BottomNavigation is used to display some important actions of the application at the bottom of the screen for easy access by users. To add the item to a BottomNavigation we need to use the BottomNavigationItem composable item.
@Composable fun BottomNavigationWithLabelComponent() { var selectedItem by remember { mutableStateOf(0) } val items = listOf("Home", "Blogs", "Profile") BottomNavigation( modifier = ().fillMaxWidth(), backgroundColor = , contentColor = ) { { index, item -> BottomNavigationItem( label = { Text(text = item) }, icon = { Icon() }, selected = selectedItem == index, onClick = { selectedItem = index } ) } } }
To use the bottom navigation without labels, you can alwaysShowLabels = false in BottomNavigationItem.
Material Checkbox
Use the checkbox when we have 2 options and the user can select or deselect options.
@Composable fun SimpleCheckboxComponent() { val checkedState = remember { mutableStateOf(true) } Row { Checkbox( checked = , modifier = (), onCheckedChange = { = it }, ) Text(text = "Checkbox Example", modifier = ()) } }
onCheckedChangecallback is used to identify changes in Checkbox.
Material ProgressBar
ProgressBar is used to display some progress that is happening in the application. For example, download progress or load data from the server.
We can make a circular progress bar or a linear progress bar.
Here is an example of a loop progress bar:
@Composable fun SimpleCircularProgressComponent() { CircularProgressIndicator( modifier = () ) }
You can also set progress = 0.4f using .
Again, you can use LinearProgressIndicator as well.
Material Slider
Slider is used to select some values from a series of values. For example, you can increase/decrease the volume through the volume slider, increase/decrease brightness through the brightness slider, etc.
The slider can be linear or there can be some discrete values, i.e. you can slide to select only allowed values, such as selecting only integer values.
@Composable fun SimpleSliderComponent() { var sliderValue by remember { mutableStateOf(0.4f) } Slider( value = sliderValue, modifier = (), onValueChange = { newValue -> sliderValue = newValue } ) Text( text = "Slider value: $sliderValue", modifier = () ) }
Similarly, you can make a step slider by passing the steps parameter to the Slider.
Material Snackbar
Snackbar is used to display some information at the bottom of the screen and place it on all UI elements.
@Composable fun SimpleSnackbarComponent() { Snackbar( modifier = (), text = { Text(text = "I'm a Simple Snackbar") } ) }
You can also add some actions to Snackbar using the following methods:
action = { Text(text = "OK", style = TextStyle(color = )) }
Custom View
In Compose, we can also make a Canvas, and on the canvas we can draw various shapes such as circles, rectangles, arcs, etc.
@Composable fun CustomViewComponent() { Canvas(modifier = ().padding()) { drawRect( color = , // topLeft is the coordinate of top-left point topLeft = Offset(0f, 0f), size = Size(800f, 400f) ) drawArc( , startAngle = 0f, sweepAngle = 120f, useCenter = true, size = Size(600f, 600f), topLeft = Offset(300f, 300f) ) } }
Crossfade animation
We can also use animations in Compose. For example, we can use Crossfade animations by using Crossfade Composable.
@Composable fun CrossFadeAnimation() { val colors = listOf(, , , ) var current by remember { mutableStateOf(colors[0]) } Column(modifier = ()) { Crossfade(current = current) { color -> Box(().clickable( onClick = { current = () } ).background(color)) Text( modifier = (), textAlign = , text = "Click To See" ) } } }
Here, the color of the Box will change with the Crossfade animation when the Box is clicked.
This is what this tutorial is about. You can try many other examples of Jetpack Compose.
Translation link:/jetpack-compose-tutorial
The above is the detailed explanation of the Jetpack Compose step-by-step guide tutorial. For more information about the Jetpack Compose step-by-step tutorial, please pay attention to my other related articles!