Jetpack Compose Basics Code Lab
The codelab can be found here: link
The first 3 parts of the lab went through the set up process and initial Composable functions. The function below is the basic function that is used to create a text view. I've had some practice before so this was nothing to write home about.
@Composable
private fun Greeting(name: String) {
Text(text = "Hello $name!")
}
Part 4: Tweaking the UI
The Surface Composable
The next part of the lab went through how to change the UI.
The code snippet supplied was:
@Composable
private fun Greeting(name: String) {
Surface(color = MaterialTheme.colorScheme.primary) {
Text (text = "Hello $name!")
}
}
The interesting part for me was the Surface
composable. My newfound understanding was that the Surface
composable is used to change the background color of the text.
Changing the color of the surface changes the background color of the text based on the theme's onXXX
color.
Modifiers
Modifiers in Compose are used to change the layout of the UI. The code snippet supplied was:
@Composable
private fun Greeting(name: String) {
Surface(color = MaterialTheme.colorScheme.primary) {
Text(text = "Hello $name!", modifier = Modifier.padding(24.dp))
}
}
Here, the Modifier.padding(24.dp)
shows how to add padding to the text.
From this, we can see the syntax of how the units are converted to Modifier-acceptable values 24.dp
.
Part 5: Reusable Composables
Note from the lab: As a best practice, your function should include a Modifier parameter that is assigned an empty Modifier by default.
@Composable
private fun MyApp(modifier: Modifier = Modifier) {
Surface(
modifier = modifier,
color = MaterialTheme.colorScheme.background
) {
Greeting("Android")
}
}
Part 6: Columns and Rows
The next part of the lab went through how to use Column
and Row
composable functions.
They also included a third one called Box
which is used to stack elements on top of each other.
I've played around with these earlier as well so I feel confident with using these composables - setting the size, padding, nesting, etc.
This part adds a button to the layout and provides a basic layout for the Button composable:
Button(
onClick = { }
) {
Text("Show less")
}
However, they point out that the Material Design Buttons spec give you other options to work with out of the box:
- Button
- ElevatedButton
- FilledTonalButton
- OutlinedButton
- TextButton
Part 7: State
State
and MutableState
are interfaces that hold some value and trigger UI updates (recompositions) whenever that value changes.
To preserve state across recompositions, remember the mutable state using remember
.
remember
is used to guard against recomposition, so the state is not reset.
@Composable
fun Greeting() {
val expanded = remember { mutableStateOf(false) }
...
}
This is how the state is read and mutated:
ElevatedButton(
onClick = { expanded.value = !expanded.value },
) {
Text(if (expanded.value) "Show less" else "Show more")
}
I find it interesting that you can make calculations based on the mutable state.
@Composable
private fun Greeting(name: String) {
val expanded = remember { mutableStateOf(false) }
val extraPadding = if (expanded.value) 48.dp else 0.dp
...
}
Part 8: State Hoisting
State that is read or modified by multiple functions should live in a common ancestor
Part 9: Lazy Lists
LazyColumn
doesn't recycle its children like RecyclerView
. It emits new Composables as you scroll through it and is still performant, as emitting Composables is relatively cheap compared to instantiating Android Views
.
Really? How come?
Part 10: Persisting State
The remember
function works only as long as the composable is kept in the Composition.
Instead of using remember
you can use rememberSaveable
. This will save each state surviving configuration changes (such as rotations) and process death.
var shouldShowOnboarding by rememberSaveable { mutableStateOf(true) }
Part 11: Animation
This code uses the animateDpAsState
function to animate the padding of the Column
composable.
It returns a State object whose value will continuously be updated by the animation until it finishes. It takes a "target value" whose type is Dp.
@Composable
private fun Greeting(name: String) {
var expanded by remember { mutableStateOf(false) }
val extraPadding by animateDpAsState(
if (expanded) 48.dp else 0.dp,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
)
)
Surface(
...
Column(modifier = Modifier
.weight(1f)
.padding(bottom = extraPadding.coerceAtLeast(0.dp))
...
)
}
Part 12: Styling and Theming
Just like my own activity to practice building my own custom Themes.