We previously looked at how to write conditional composable with the price component. In this article, we’ll develop a new component, named quantity selection, and see how we can handle an internal state inside and how to get its value when a user interact with it.
Disclaimer: All source code exposed here has been developed with artifact 0.1.0-dev17 of Compose. Because Jetpack Compose is still in an early developer preview, note that some source code may change with new versions.
Quantity selection component
When you build a retail Android application, you need a component to select quantities needed. At Decathlon, a component has been designed for this case.
- Minimum value can’t be negative, by default it’s 0 and if the current quantity is 0, the minus button is disabled with a grey color.
- Maximum value is optional, by default it’s the max value of an integer and if you define a maximum, the increment button is disabled when the max value is reached.
- You can edit the quantity when you press the text field, it takes the focus and the bottom bar become green. When the focus is lost, you go back to its default state.
That makes it the perfect candidate for our topic because it retains its current quantity and notifies its parent composable when the value changes.
State variable declaration
There is no state saved between two screen compositions. Composable can take a model in input and Compose will draw the expected visual. When you don’t declare an explicit state, we say your Composable is stateless.
This is a pretty good practice to keep state as small as possible to avoid side effects. But in our case we want to save a data between two renderings. To do so there are 2 types of functions available. First one is called remember and the second one state.
- remember saves the value produced by a lambda in parameter. This lambda will be evaluated during the composition and each recomposition will always return the value produced by composition.
- state is used to locally mutate and use data within the composition context.
We’ll focus on state function for our topic. Remember function might be described in another article.
We declare a QuantitySelection function which is our Composable and take several parameters:
- value is the initial value of the component.
- maxValue is our optional maximum value sets to Int.MAX_VALUE by default.
- onValueChanged will be triggered whenever the value is modified from the text field, minus or more buttons.
- onMinusClicked will be triggered whenever the user press the minus button.
- onMoreClicked will be triggered whenever the user press the more button.
Note that the state isn’t declared as parameter of the Composable but can be initialized by values of parameters. The lambda of the state function will be evaluated during the first composition and at each change on the variable quantityState, it’ll force the recomposition of our component!
Note: You don’t need to declare a data class to save a state. A state function can take a primitive type as parameter. Depends on what you need and what you want.
Modify state value
Let’s focus on the minus button to see how we can change the value of a state and use it to update UI.
In the Box, we declare a clickable modifier to handle changes of the state but we need to disable this behavior if the button is disabled and change the color of the icon.
In the clickable callback, we implement the UI logic to decrement the quantity value if the current value isn’t negative. To get our QuantityState object value inside a state variable, we need to call the value property. This value is mutable and can be changed by a simple assignment. Our implementation is pretty simple:
When the callback is evaluated and the state modified, it’ll force recomposition of our Composable and our UI can react with the new value of our internal quantity state value:
To disable our button or to change the color of our icon, we use the value of our internal state. When the quantity will be 0, our button is no more clickable and the color change to greyLight1.
The principle is the exact same for the more button and for our text field! Our component is finished and can be used everywhere in our application.
In this post, we’ve taken a quick dive into how to handle internal state in a Composable component with state function provided by Jetpack Compose library.