2

Animating visibility vs alpha in Compose

 1 year ago
source link: https://www.valueof.io/blog/animatedvisibility-animate-float-as-state-alpha-position
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

June 12, 2022

IMG_8987.JPG

Let’s say you are building a layout that contains a Column with an Image and a Button below it and the button triggers fade in and fade out of the image. Jetpack Compose makes it very easy to do with help of AnimatedVisibility composable.

AnimatedVisibility

setContent {
  MyApplicationTheme {
    Surface(
      modifier = Modifier
        .fillMaxSize(),
      color = MaterialTheme.colors.background
    ) {

      var imageVisible by remember { mutableStateOf(false) }

      Column(
        modifier = Modifier.fillMaxSize(),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
      ) {
        AnimatedVisibility(
          visible = imageVisible,
          enter = fadeIn(animationSpec = tween(2000)),
          exit = fadeOut(animationSpec = tween(2000))
        ) {
          Image(
            painter = painterResource(id = R.drawable.boats),
            contentDescription = "Boats",
            modifier = Modifier
              .padding(horizontal = 16.dp)
          )
        }
        Button(
          onClick = { imageVisible = !imageVisible }) {
          Text("Click me")
        }
      }
    }
  }
}

We get this UI as a result:

animated-visibility.gif

Notice that the Column composable sets verticalArrangement = Arrangement.Center for its children. Because of that, in order to stay in the center vertically, the button changes its position every time the image appears and disappears.

Let’s examine the behavior using Layout Inspector.

When AnimatedVisibility is not a part of the composition (no content to display, i.e. no Image to display), the Column contains Button only and it’s centered within its container. See below:

Screen+Shot+2022-06-12+at+10.46.10+PM.png

When AnimatedVisibility is a part of the composition (i.e. Image is displayed), the Column contains AnimatedVisibility>Image and Button. See below:

Screen+Shot+2022-06-12+at+10.45.26+PM.png

Here is the relevant portion of the AnimatedVisibility documentation:

[AnimatedVisibility] creates a custom [Layout] for its content. The size of the custom layout is determined by the largest width and largest height of the children. 

Once the exit transition is finished, the [content] composable will be removed from the tree, and disposed. 

In the View system, this is similar to using Visibility.GONE on the Image—when set, the view gets removed from the View hierarchy.

Let’s look at an alternative way to accomplish this but ensure the button always stays in the same position.

animateFloatAsState

One of the ways to accomplish this is to always add the Image to the composition but show and hide it using animated alpha using animateFloatAsState:

alpha.gif

Here is the code that animates image alpha rather than animating image visibility.

    setContent {
      MyApplicationTheme {
        Surface(
          modifier = Modifier
            .fillMaxSize(),
          color = MaterialTheme.colors.background
        ) {

          var imageVisible by remember { mutableStateOf(false) }

          val imageAlpha: Float by animateFloatAsState(
            targetValue = if (imageVisible) 1f else 0f,
            animationSpec = tween(
              durationMillis = 2000,
              easing = LinearEasing,
            )
          )

          Column(
            modifier = Modifier.fillMaxSize(),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.Center
          ) {
            Image(
              painter = painterResource(id = R.drawable.boats),
              contentDescription = "Boats",
              alpha = imageAlpha,
              modifier = Modifier
                .padding(horizontal = 16.dp)
            )
            Button(
              onClick = { imageVisible = !imageVisible }) {
              Text("Click me")
            }
          }
        }
      }
    }
  }

Let’s look at the Layout Inspector again.

Here is the layout when the Image alpha is 0.0

Screen+Shot+2022-06-12+at+11.04.08+PM.png

And here is the layout when the alpha is 1.0

Screen+Shot+2022-06-12+at+11.08.09+PM.png

In both cases, animating alpha value causes the Image composable function to recompose itself. Because the Image is always a part of the composition during the state changes, the Button never changes its position.

Learn about other animate*AsState and get more examples of Animation APIs in Compose at https://developer.android.com/jetpack/compose/animation


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK