Handle UI Change OnClick with Jetpack Compose
Tags: Mobile App Development, Android App Development, AndroidDev, Android, Jetpack Compose

Learning Android Development

Handle UI Change OnClick with Jetpack Compose

Understand Jetpack Compose State and UI Recompose

Photo by Andreas Haslinger on Unsplash

Early this week, I share how to draw simple clock animation using Jetpack Compose as per the blog below.

It’s an App that keeps updating its screen upon startup, using animateFloat object.

Now let’s explore how to have a button to click start and stop the animation, and restart it again. Although it seems simple, there are many learnings of Jetpack Compose way of working one could get out of it. (show below is additional start/stop button to start the animation.

The just animation model

Before we explore a clickable start-stop clock, let’s look the structure the Clock composable function we previously had.

In it, there’s a an OnActive function that is called once upon the Composable function drawn for the first time. It kicks off the animationFloat to animate. After that, it will not. be called again, until a new Composable Clock is called again.

After the animationFloat has started the animation, it’s value will continue to change. As inside the Clock composable function, it keeps on accessing the new state value from animationFloat , the Clock got recompose and hence redrawn each cycle upon update of the value. This create the animation like effect.

Adding a toggle button.

To make a toggle button, similar to the Clock composable, we make a ToggleButton Composable function, that has a toggleState boolean state.

Upon changes of the toggleState value, the Text value will be changed accordingly.

There’s no need of OnActive here as the toggleState value can be initially upon the start calling of the function, instead of start of drawing (like the animation Clock needed).

You can get a detail description of how the composable ToggleButton works and it’s comparison with the conventional Android View way of doing in the below article.

Putting all together

To put everything together, we have setContent which contain a Column , which has the Clock composable and Toggle composable

setContent {

Column(

verticalArrangement = Arrangement.Center,

horizontalAlignment = Alignment.CenterHorizontally

) {

Clock(modifier = Modifier

.aspectRatio(1.0f)

.padding(64.dp))

Toggle(modifier = Modifier)

}

}

The important note is to know where we need to access the state value. by accessing the state value, the composable function is be recompose (redrawn).

Note: if we access the state value in Column , then both the Clock and Toggle will get redrawn, and hence making strange unexplanatble drawing update behavior.

Triggering the start and stop of animation

In the above diagram, one major missing point is, how can the button trigger the animation start and stop, since the toggle value state has to be fully decoupled.

Do note the Clock is a Composable function, hence there’s no way for the MainActivity to access to the animationFloat value inside Clock to start. or stop the animation.

To solve the problem, we introduce another stateToggle called animationToggle . This value is in the MainActivity scope, but it is

Inject animationToggle into the Clock composable to control the start and stop of the animation.

into the composable to control the start and stop of the animation. The ToggleButton has a callback function. We use that callback function to triggered the animationToggle .

With that, we link up the ToggleButton and Clock composable functions , without affecting the MainActivity external view need to be recomposed.

class MainActivity : AppCompatActivity() {



private val animationToggle = mutableStateOf(false)

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)



setContent {

Column(

verticalArrangement = Arrangement.Center,

horizontalAlignment = Alignment.CenterHorizontally

) {

Clock(modifier = Modifier

.aspectRatio(1.0f)

.padding(64.dp),

animationToggle)

Toggle(modifier = Modifier) {

animationToggle.value = it

}

}

}

}

}

You can get the entire code here.