# WindowInsetsAnimation

Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/layout/WindowInsetsRulers.kt+class:androidx.compose.ui.layout.WindowInsetsAnimation) Added in [1.9.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.9.0) Common/AllAndroid/JVM
- Cmn

  ```
  sealed interface WindowInsetsAnimation
  ```

*** ** * ** ***

Provides properties related to animating `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsRulers`.

## Summary

| ### Public properties |
|---|---|---|
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-float/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#alpha()` The translucency of the animating window. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-long/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#durationMillis()` The duration of the animation in milliseconds. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-float/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#fraction()` The current fraction of the animation if the Window Insets are being animated or `0` if `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isAnimating()` is `false`. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isAnimating()` True when the Window Insets are currently being animated. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isVisible()` True when the Window Insets are visible. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/RectRulers` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#source()` The starting insets values of the animation when the insets are animating (`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isAnimating()` is `true`). | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/RectRulers` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#target()` The ending insets values of the animation when the insets are animating (`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isAnimating()` is `true`). | Cmn |

## Public properties

### alpha

Cmn Added in [1.9.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.9.0)

```
val alpha: Float
```

The translucency of the animating window. This is used when Window Insets animate by fading and can be used to have content match the fade.

```kotlin
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.WindowInsetsRulers
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints

Layout(
    modifier = Modifier.fillMaxSize(),
    content = {
        Box(Modifier.background(Color.Blue)) // status bar background
        Box(Modifier.background(Color.Yellow)) // navigation bar background on bottom
        Box(Modifier.background(Color.White)) // content between top and bottom
    },
    measurePolicy = { measurables, constraints ->
        val width = constraints.maxWidth
        val height = constraints.maxHeight
        layout(width, height) {
            val top = WindowInsetsRulers.StatusBars.current.top.current(0f).roundToInt()
            val bottom =
                WindowInsetsRulers.NavigationBars.current.bottom.current(0f).roundToInt()
            measurables[0].measure(Constraints.fixed(width, top)).placeWithLayer(0, 0) {
                alpha = WindowInsetsRulers.StatusBars.getAnimation(this@layout).alpha
            }
            measurables[2].measure(Constraints.fixed(width, height - bottom)).place(0, bottom)
            measurables[1].measure(Constraints.fixed(width, bottom - top)).placeWithLayer(
                0,
                top,
            ) {
                alpha = WindowInsetsRulers.NavigationBars.getAnimation(this@layout).alpha
            }
        }
    },
)
```

### durationMillis

Cmn Added in [1.9.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.9.0)

```
val durationMillis: Long
```

The duration of the animation in milliseconds.

### fraction

Cmn Added in [1.9.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.9.0)

```
val fraction: Float
```

The current fraction of the animation if the Window Insets are being animated or `0` if `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isAnimating()` is `false`. When animating, `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#fraction()` typically ranges between `0` at the start to `1` at the end, but it may go out of that range if an interpolator causes the fraction to overshoot the range.

### isAnimating

Cmn Added in [1.9.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.9.0)

```
val isAnimating: Boolean
```

True when the Window Insets are currently being animated.

### isVisible

Cmn Added in [1.9.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.9.0)

```
val isVisible: Boolean
```

True when the Window Insets are visible. For example, for `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsRulers#StatusBars()`, when a status bar is shown, `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isVisible()` will be `true`. When the status bar is hidden, `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isVisible()` will be `false`. `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isVisible()` remains `true` during animations.

### source

Cmn Added in [1.9.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.9.0)

```
val source: RectRulers
```

The starting insets values of the animation when the insets are animating (`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isAnimating()` is `true`). When the insets are not animating, no ruler values will be provided.

```kotlin
import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material3.TextField
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.WindowInsetsRulers
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.dp

Column(Modifier.fillMaxSize()) {
    // TextField will show the IME when it is focused.
    TextField("HelloWorld", {}, Modifier.fillMaxWidth())
    // When the IME shows, animate the content to align with the top of the IME.
    // When the IME hides, animate the content to the top of the Box.
    val verticalPosition = remember { Animatable(0f) }
    val coroutineScope = rememberCoroutineScope()
    Box(
        Modifier.fillMaxSize().background(Color.Yellow).layout { measurable, constraints ->
            if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) {
                layout(constraints.maxWidth, constraints.maxHeight) {
                    val placeable =
                        measurable.measure(constraints.copy(minWidth = 0, minHeight = 0))
                    val ime = WindowInsetsRulers.Ime
                    val animationProperties = ime.getAnimation(this)
                    val height = constraints.maxHeight.toFloat()
                    val sourceBottom = animationProperties.source.bottom.current(height)
                    val targetBottom = animationProperties.target.bottom.current(height)
                    val targetPosition =
                        if (!animationProperties.isVisible || sourceBottom < targetBottom) {
                            // IME is either not visible or animating away
                            0f
                        } else if (animationProperties.isAnimating) {
                            // IME is visible and animating
                            targetBottom - placeable.height
                        } else {
                            // IME is visible and not animating, so use the IME poosition
                            ime.current.bottom.current(height) - placeable.height
                        }
                    if (targetPosition != verticalPosition.targetValue) {
                        coroutineScope.launch { verticalPosition.animateTo(targetPosition) }
                    }
                    placeable.place(0, verticalPosition.value.roundToInt())
                }
            } else {
                // It should only get here if inside scrollable content or aligning to an
                // alignment
                // line.
                val placeable = measurable.measure(constraints)
                layout(placeable.width, placeable.height) { placeable.place(0, 0) }
            }
        }
    ) {
        // content
        Box(Modifier.size(100.dp).background(Color.Blue))
    }
}
```

### target

Cmn Added in [1.9.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.9.0)

```
val target: RectRulers
```

The ending insets values of the animation when the insets are animating (`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/WindowInsetsAnimation#isAnimating()` is `true`). When the insets are not animating, no ruler values will be provided.

```kotlin
import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.size
import androidx.compose.material3.TextField
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.WindowInsetsRulers
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.dp

Column(Modifier.fillMaxSize()) {
    // TextField will show the IME when it is focused.
    TextField("HelloWorld", {}, Modifier.fillMaxWidth())
    // When the IME shows, animate the content to align with the top of the IME.
    // When the IME hides, animate the content to the top of the Box.
    val verticalPosition = remember { Animatable(0f) }
    val coroutineScope = rememberCoroutineScope()
    Box(
        Modifier.fillMaxSize().background(Color.Yellow).layout { measurable, constraints ->
            if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) {
                layout(constraints.maxWidth, constraints.maxHeight) {
                    val placeable =
                        measurable.measure(constraints.copy(minWidth = 0, minHeight = 0))
                    val ime = WindowInsetsRulers.Ime
                    val animationProperties = ime.getAnimation(this)
                    val height = constraints.maxHeight.toFloat()
                    val sourceBottom = animationProperties.source.bottom.current(height)
                    val targetBottom = animationProperties.target.bottom.current(height)
                    val targetPosition =
                        if (!animationProperties.isVisible || sourceBottom < targetBottom) {
                            // IME is either not visible or animating away
                            0f
                        } else if (animationProperties.isAnimating) {
                            // IME is visible and animating
                            targetBottom - placeable.height
                        } else {
                            // IME is visible and not animating, so use the IME poosition
                            ime.current.bottom.current(height) - placeable.height
                        }
                    if (targetPosition != verticalPosition.targetValue) {
                        coroutineScope.launch { verticalPosition.animateTo(targetPosition) }
                    }
                    placeable.place(0, verticalPosition.value.roundToInt())
                }
            } else {
                // It should only get here if inside scrollable content or aligning to an
                // alignment
                // line.
                val placeable = measurable.measure(constraints)
                layout(placeable.width, placeable.height) { placeable.place(0, 0) }
            }
        }
    ) {
        // content
        Box(Modifier.size(100.dp).background(Color.Blue))
    }
}
```