title: Jetpack compose animate open box
body: <p>I'm new to jetpack compose and animation. I wanted to experiement with some specific custom animation and try to get a better grasp of all this.</p>
  <p>I want to make a specific <strong>Box composable animate (Box/Surface/Column/View it doesn't matter, just a background view)from the center to the width</strong> and once the width arrives to the sides <strong>then open the box increasing its height and showing the Text content inside that Box</strong> as its opens.</p>
  <p><a href="https://developer.android.com/jetpack/compose/animation#animationvector" rel="nofollow noreferrer">I already took a look at this animation page</a> but I'm not still sure if AnimationVector is the way to go.</p>
  <p>What should I look into for creating animations like these in jetpack compose? Is it possible?</p>
  <p>Edit: Graphic examples of what I want to achieve.</p>
  <ol>
  <li>Hidden</li>
  <li>Open width with 400ms duration. (Height should be very low but noticeable)</li>
  <li>Increase height once width reached the end of the animation.
  3.1 Text starts to fade in as height reaches the mid point. (This idea is not needed to be this sophisticated but looks cool)</li>
  </ol>
  <p><a href="https://i.stack.imgur.com/ibrer.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ibrer.png" alt="enter image description here" /></a></p>
  <p>Edit update:
  I think I have almost achieved it. Think this is the baseline I was asking on this post. I'll let the code here just in case someone wants to take a look:</p>
  <pre><code>@ExperimentalAnimationApi
  @Composable
  fun MessageBoxAnimated() {
      var text =
          &quot;Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.&quot;
  
      var widthState by remember { mutableStateOf(10.dp) }
      val width by animateDpAsState(
          targetValue = widthState,
          tween(
              durationMillis = 800,
              easing = LinearOutSlowInEasing
          )
      )
  
      var heightState by remember { mutableStateOf(10.dp) }
      val height by animateDpAsState(
          targetValue = heightState,
          tween(
              delayMillis = 800,
              durationMillis = 800,
              easing = LinearOutSlowInEasing
          )
      )
  
      var textVisibility = remember { MutableTransitionState(false) }
  
      var textWidth by remember { mutableStateOf(0) }
      var textHeight by remember { mutableStateOf(0) }
  
      /***
       * IGNORE THIS COLUMN SECTION.
       * This is needed as a final result, it's the same as below 
       * but is a reference so I can get the width/height of the text and apply
       * to the animation.
       * TLDR: So yeah this is basically a copy of the same thing but placed before starting the animation so I know what is the width/height. Yes it's invisible, user won't know there's a duplicate.
       */
      Column(modifier = Modifier
          .fillMaxSize()
          .background(MaterialTheme.colors.background)) {
          Column(
              horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, modifier = Modifier
                  .wrapContentWidth()
                  .wrapContentHeight()
                  .background(MaterialTheme.colors.background)
                  .padding(20.dp)
          ) {
              Text(
                  text = text,
                  modifier = Modifier
                      .padding(20.dp)
                      .background(MaterialTheme.colors.background)
                      .onSizeChanged {
                          textWidth = (it.width.toFloat() / 2.2.toFloat()).toInt()
                          textHeight = (it.height.toFloat() / 2.2.toFloat()).toInt()
                      }
                      ,
                  color = MaterialTheme.colors.background,
                  fontFamily = FontFamily.SansSerif
              )
          }
      }
  
      /**
       * Here's where the magic happens. Animation is here.
       */
      Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, modifier = Modifier.padding(20.dp)) {
          Column(
              Modifier
                  .width(width)
                  .height(height)
                  .background(Color.Gray),
              verticalArrangement = Arrangement.Center,
              horizontalAlignment = Alignment.CenterHorizontally
          ) {
              //This AnimatedVisibility doesn't work and acts like it comes from the bottom instead of just fading in
              AnimatedVisibility(
                  visibleState = textVisibility,
                  enter = fadeIn(animationSpec = tween(delayMillis = 1000, durationMillis = 1000))
              ) {
                  Text(
                      text = text,
                      modifier = Modifier
                          .padding(20.dp)
                          .animateContentSize()
                      ,
                      color = MaterialTheme.colors.onBackground,
                      fontFamily = FontFamily.SansSerif
                  )
              }
          }
  
          Button(
              onClick = {
                  //Apply width/height of the hidden final result
                  widthState += textWidth.dp 
                  heightState += textHeight.dp
                  textVisibility.targetState = true //Invoke text animation
              }, colors = ButtonDefaults.buttonColors(
                  backgroundColor = Color.Blue
              )
          ) {
              Text(text = &quot;Press here&quot;, color = Color.White)
          }
      }
  }
  </code></pre>