A list,

Jetpack Compose is Google’s new Android toolkit for building native interfaces that simplify and speed up interface development on Android. Jetpack Compose is a declarative UI framework that marks the beginning of Android’s full embrace of declarative UI development. Jetpack Compose has many advantages: simpler code, more efficient application development, more intuitive Kotlin API features, and more powerful preview tools.

Second, development environment

For a better development experience, I use the Android Studio Canary version, which eliminates the need for Settings and dependencies. (Download address)

Open the project and create the Empty Compose activity template. Note that the build.gradle in the root directory should correspond to the com.android.tools.build and org.jetBrains. Kotlin. Otherwise, an error may occur. Here we use:

Dependencies {classpath "com. Android. Tools. Build: gradle: 7.0.0 - alpha15" classpath "Org. Jetbrains. Kotlin: kotlin - gradle - plugin: 1.4.30"}Copy the code

This completes the creation of the project.

Jetpack Compose animation

Jetpack Compose provides powerful and extensible apis that can be used to easily implement a variety of animation effects in the application interface. Common methods for Jetpack Compose Animations are described below.

3.1 State-driven animation :State

The Jetpack Compose animation enables the UI to update automatically by listening for changes in state values. Composable functions can listen for changes in state values using remember or mutableStateOf. If the state value is constant, the remember function retains that value in each recombination; If the state is mutable, it triggers reorganization when the value changes, and mutableStateOf gets a MutableState object, which is an observable type.

This recombination is key to creating state-driven animations. With reorganization, they are triggered when there is any change in the state of the composable component. Compose animation is state-driven, and the animation-related API is relatively easy to learn, making it easier to create beautiful declarative animations.

3.2 Visibility animation: AnimatedVisibility

Let’s start with the function definition:

@ExperimentalAnimationApi
@Composable
fun AnimatedVisibility(
    visible: Boolean,
    modifier: Modifier = Modifier,
    enter: EnterTransition = fadeIn() + expandIn(),
    exit: ExitTransition = shrinkOut() + fadeOut(),
    initiallyVisible: Boolean = visible,
    content: @Composable () -> Unit
) {
    AnimatedVisibilityImpl(visible, modifier, enter, exit, initiallyVisible, content)
}
Copy the code

As you can see, the default animation is fade in to zoom in and fade out to shrink. In practice, different functions are passed in to achieve various dynamic effects.

AnimatedVisibility AnimatedVisibility animates the appearance and disappearance of its content as the visible value changes. The following code can control the appearance and disappearance of pictures by clicking Button.

@composable fun AinmationDemo() {//AnimatedVisibility var visible by remember {mutableStateOf(true)} Column(Composable fun AinmationDemo() {Composable fun AinmationDemo() {//AnimatedVisibility var visible by remember {mutableStateOf(true)} Column( Modifier .fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Button( onClick = { visible = ! visible } ) { Text(text = if (visible) "Hide" else "Show") } Spacer(Modifier.height(16.dp)) AnimatedVisibility( visible = visible, enter = slideInVertically() + fadeIn(), exit = slideOutVertically() + fadeOut() ) { Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier.fillMaxSize() ) } } }Copy the code

By monitoring the change of visible, the visible animation of the picture can be realized, and the effect is shown in the small picture.

3.3 Layout Size animation: AnimateContentSize

Let’s look at the function definition:

fun Modifier.animateContentSize(
    animationSpec: FiniteAnimationSpec<IntSize> = spring(),
    finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null
)
Copy the code

You can set the animation speed and listening values for layout size animations.

The function definition shows that this function is essentially an extension of Modefier. You can animate the layout size by listening for state changes using the size variable as follows:

AnimateContentSize var size by remember {mutableStateOf(size (300F, 300F)) } Column( Modifier .fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Spacer(Modifier.height(16.dp)) Button( onClick = { size = if (size.height == 300F) { Size(500F, 500F) } else { Size(300F, 300F) } } ) { Text(if (size.height == 300F) "Shrink" else "Expand") } Spacer(Modifier.height(16.dp)) Box( Modifier .animateContentSize() ) { Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier.animatecontentSize ().size(size = size.height.dp))}} // Use the Modifier to modify animateContentSize var size by remember { mutableStateOf(Size(300F, 300F)) } Column( Modifier .fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Spacer(Modifier.height(16.dp)) Button( onClick = { size = if (size.height == 300F) { Size(500F, 500F) } else { Size(300F, 300F) } } ) { Text(if (size.height == 300F) "Shrink" else "Expand") } Spacer(Modifier.height(16.dp)) Box( Modifier .animateContentSize() ) { Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier .animateContentSize() .size(size = size.height.dp) ) }}Copy the code

Click Button to monitor the change of size value and use animateContentSize () to achieve the animation effect, as shown below:

3.4 Layout switching animation: Crossfade

Crossfade can be used to animate between two layouts by listening for changes in state values and using a fade in and out animation. The function itself is a Composable as follows:

Var fadeStatus by remember {mutableStateOf(true)} Column(Modifier.fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Button( onClick = { fadeStatus = ! fadeStatus } ) { Text(text = if (fadeStatus) "Fade In" else "Fade Out") } Spacer(Modifier.height(16.dp)) Crossfade(targetState = fadeStatus, animationSpec = tween(3000)) { screen -> when (screen) { true -> Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier .animateContentSize() .size(300.dp) ) false -> Image( painter = painterResource(id = R.drawable.pikaqiu2), contentDescription = null, Modifier .animateContentSize() .size(300.dp) ) } } }Copy the code

Also, by listening to the value of fadeStatus, the animation of layout switching is realized. The specific dynamic effect is shown in the figure:

3.5 Single-value animation: Animate *AsState

Animates a single value. Simply provide the end value (or target value) and the API plays the animation to the specified value starting from the current value.

Jetpack Compose provides a number of built-in functions to animate different types of data, for example: AnimateColorAsState, animateDpAsState, animateOffsetAsState, animateFooAsState, animateFooAsState Var transparent by remember {mutableStateOf(true)} val alpha: Float by animateFloatAsState(if (transparent) 1f else 0.5f) Column(Modifier.fillMaxWidth().fillmaxHeight (), Float by animateFloatAsState(if (transparent) 1f else 0.5f) Column(Modifier.fillMaxWidth().fillmaxHeight (), Arrangement.Top, Alignment.CenterHorizontally ) { Button( onClick = { transparent = ! transparent } ) { Text(if (transparent) "Light" else "Dark") } Spacer(Modifier.height(16.dp)) Box { Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier .animateContentSize() .graphicsLayer(alpha = alpha) .size(300.dp) ) } }Copy the code

The animation effect is shown below:

3.6 Combining Animations: updateTransition

Transition tracks one or more animations simultaneously and synchronizes them across multiple states. The specific code is as follows:

var imagePosition by remember { mutableStateOf(ImagePosition.TopLeft) }

    Column(
        Modifier
            .fillMaxWidth()
            .fillMaxHeight(),
        Arrangement.Top,
        Alignment.CenterHorizontally
    ) {
        Spacer(Modifier.height(16.dp))

        val transition = updateTransition(targetState = imagePosition, label = "")
        val boxOffset by transition.animateOffset(label = "") { position ->
            when (position) {
                ImagePosition.TopLeft -> Offset(-60F, 0F)
                ImagePosition.BottomRight -> Offset(60F, 120F)
                ImagePosition.TopRight -> Offset(60F, 0F)
                ImagePosition.BottomLeft -> Offset(-60F, 120F)
            }
        }
        Button(onClick = {
            imagePosition = ChangePosition(imagePosition)
        }) {
            Text("Change position")
        }
        Box {

            Image(
                painter = painterResource(id = R.drawable.pikaqiu),
                contentDescription = null,
                Modifier
                    .offset(boxOffset.x.dp, boxOffset.y.dp)
                    .animateContentSize()
                    .size(300.dp)
            )
        }
}
Copy the code

ImagePosition and ChangePosition are enumerated classes and custom functions defined respectively.

enum class ImagePosition {
    TopRight,
    TopLeft,
    BottomRight,
    BottomLeft
}

fun ChangePosition(position: ImagePosition) =
    when (position) {
        ImagePosition.TopLeft -> ImagePosition.BottomRight
        ImagePosition.BottomRight -> ImagePosition.TopRight
        ImagePosition.TopRight -> ImagePosition.BottomLeft
        ImagePosition.BottomLeft -> ImagePosition.TopLeft
    }
Copy the code

The animation looks like this:

Four, conclusion

Jetpack Compose has simplified animation to the point where you can just create declarative code in our composable functions, just write the way you want your UI to animate, and let Compose manage the rest. Finally, this is the main goal of Jetpack Compose: to create a declarative UI toolkit to speed up application development and improve code readability and logic.

Jetpack Compose provides a declarative UI toolkit that does more with less code and makes the code much more readable and logical.

For example

Android advanced development combat tutorial: Compose drawing and View system comparison analysis