시배's Android

Compose Docs | Animation modifiers and composables 본문

Android/Compose Docs

Compose Docs | Animation modifiers and composables

si8ae 2023. 9. 21. 18:30
 

Animation modifiers and composables  |  Jetpack Compose  |  Android Developers

Animation modifiers and composables Stay organized with collections Save and categorize content based on your preferences. Compose comes with built-in composables and modifiers for handling common animation use cases. Built-in animated composables Animate

developer.android.com

Built-in animated composables

Animate appearance and disappearance with AnimatedVisibility

AnimatedVisibility 컴포저블은 콘텐츠의 모양과 사라짐을 애니메이션으로 표현합니다.

var editable by remember { mutableStateOf(true) }
AnimatedVisibility(visible = editable) {
    Text(text = "Edit")
}

기본적으로 콘텐츠는 페이드 확장으로 나타나고 페이드 아웃 축소로 사라집니다. EnterTransition ExitTransition 지정하여 전환을 사용자 지정할 있습니다.

var visible by remember { mutableStateOf(true) }
val density = LocalDensity.current
AnimatedVisibility(
    visible = visible,
    enter = slideInVertically {
        // Slide in from 40 dp from the top.
        with(density) { -40.dp.roundToPx() }
    } + expandVertically(
        // Expand from the top.
        expandFrom = Alignment.Top
    ) + fadeIn(
        // Fade in with the initial alpha of 0.3f.
        initialAlpha = 0.3f
    ),
    exit = slideOutVertically() + shrinkVertically() + fadeOut()
) {
    Text("Hello", Modifier.fillMaxWidth().height(200.dp))
}

위의 예에서 있듯이 + 연산자를 사용하여 여러 개의 EnterTransition 또는 ExitTransition 객체를 결합할 있으며, 객체는 선택적 매개 변수를 허용하여 동작을 사용자 지정할 있습니다. 자세한 내용은 참조를 참조하세요. 

EnterTransition ExitTransition
fadeIn

fadeOut

slideIn


slideOut


slideInHorizontally

slideOutHorizontally


slideInVertically

slideOutVertically


scaleIn


scaleOut


expandIn


shrinkOut


expandHorizontally


shrinkHorizontally


expandVertically


shrinkVertically


AnimatedVisibility MutableTransitionState 취하는 변형도 제공합니다. 이를 통해 AnimatedVisibility 컴포지션 트리에 추가되는 즉시 애니메이션을 트리거할 있습니다. 애니메이션 상태를 관찰할 때도 유용합니다.

// Create a MutableTransitionState<Boolean> for the AnimatedVisibility.
val state = remember {
    MutableTransitionState(false).apply {
        // Start the animation immediately.
        targetState = true
    }
}
Column {
    AnimatedVisibility(visibleState = state) {
        Text(text = "Hello, world!")
    }

    // Use the MutableTransitionState to know the current animation state
    // of the AnimatedVisibility.
    Text(
        text = when {
            state.isIdle && state.currentState -> "Visible"
            !state.isIdle && state.currentState -> "Disappearing"
            state.isIdle && !state.currentState -> "Invisible"
            else -> "Appearing"
        }
    )
}

 

Animate enter and exit for children

AnimatedVisibility 내의 콘텐츠(직접 또는 간접 자식)는 animateEnterExit 모디파이어를 사용하여 각각에 대해 서로 다른 애니메이션 동작을 지정할 수 있습니다. 이러한 각 자식에 대한 시각적 효과는 AnimatedVisibility 컴포저블에 지정된 애니메이션과 자식 자체의 진입 및 종료 애니메이션의 조합으로 이루어집니다.

var visible by remember { mutableStateOf(true) }

AnimatedVisibility(
    visible = visible,
    enter = fadeIn(),
    exit = fadeOut()
) {
    // Fade in/out the background and the foreground.
    Box(Modifier.fillMaxSize().background(Color.DarkGray)) {
        Box(
            Modifier
                .align(Alignment.Center)
                .animateEnterExit(
                    // Slide in/out the inner box.
                    enter = slideInVertically(),
                    exit = slideOutVertically()
                )
                .sizeIn(minWidth = 256.dp, minHeight = 64.dp)
                .background(Color.Red)
        ) {
            // Content of the notification…
        }
    }
}

경우에 따라 애니메이션이 전혀 적용되지 않도록 하여 자식들이 각각 고유한 애니메이션을 animateEnterExit 의해 가질 있도록 하고 싶을 있습니다. 이렇게 하려면 AnimatedVisibility 컴포저블에서 EnterTransition.None ExitTransition.None 지정하면 됩니다.

Add custom animation

내장된 시작 및 종료 애니메이션 외에 커스텀 애니메이션 효과를 추가하려면 AnimatedVisibility에 대한 콘텐츠 람다 내부의 transition 속성을 통해 기본 트랜지션 인스턴스에 액세스하세요. 트랜지션 인스턴스에 추가된 모든 애니메이션 상태는 AnimatedVisibility의 진입 및 종료 애니메이션과 동시에 실행됩니다. AnimatedVisibility는 트랜지션의 모든 애니메이션이 완료될 때까지 기다렸다가 해당 콘텐츠를 제거합니다. Transition과 독립적으로 생성된 종료 애니메이션의 경우(예: animate*AsState 사용) AnimatedVisibility가 이를 고려할 수 없으므로 완료되기 전에 컴포저블 콘텐츠가 제거될 수 있습니다.

var visible by remember { mutableStateOf(true) }

AnimatedVisibility(
    visible = visible,
    enter = fadeIn(),
    exit = fadeOut()
) { // this: AnimatedVisibilityScope
    // Use AnimatedVisibilityScope#transition to add a custom animation
    // to the AnimatedVisibility.
    val background by transition.animateColor(label = "color") { state ->
        if (state == EnterExitState.Visible) Color.Blue else Color.Gray
    }
    Box(modifier = Modifier.size(128.dp).background(background))
}

Animate based on target state with AnimatedContent

Row {
    var count by remember { mutableStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Add")
    }
    AnimatedContent(targetState = count) { targetCount ->
        // Make sure to use `targetCount`, not `count`.
        Text(text = "Count: $targetCount")
    }
}

항상 람다 매개변수를 사용하여 콘텐츠에 반영해야 한다는 점에 유의하세요. API는 이 값을 키로 사용하여 현재 표시되는 콘텐츠를 식별합니다.

 

기본적으로 초기 콘텐츠가 페이드 아웃된 다음 대상 콘텐츠가 페이드 인됩니다( 동작을 페이드 스루라고 ). transitionSpec 매개 변수에 ContentTransform 객체를 지정하여 애니메이션 동작을 사용자 지정할 있습니다. with 접두사 함수를 사용하여 엔터 트랜지션과 출구 트랜지션을 결합하여 콘텐츠 트랜스폼을 만들 있습니다. SizeTransform using 접두사 함수로 연결하여 ContentTransform 적용할 있습니다.

AnimatedContent(
    targetState = count,
    transitionSpec = {
        // Compare the incoming number with the previous number.
        if (targetState > initialState) {
            // If the target number is larger, it slides up and fades in
            // while the initial (smaller) number slides up and fades out.
            slideInVertically { height -> height } + fadeIn() with
                slideOutVertically { height -> -height } + fadeOut()
        } else {
            // If the target number is smaller, it slides down and fades in
            // while the initial number slides down and fades out.
            slideInVertically { height -> -height } + fadeIn() with
                slideOutVertically { height -> height } + fadeOut()
        }.using(
            // Disable clipping since the faded slide-in/out should
            // be displayed out of bounds.
            SizeTransform(clip = false)
        )
    }
) { targetCount ->
    Text(text = "$targetCount")
}

EnterTransition은 대상 콘텐츠가 어떻게 표시되어야 하는지 정의하고 ExitTransition은 초기 콘텐츠가 어떻게 사라져야 하는지 정의합니다. AnimatedVisibility에 사용할 수 있는 모든 EnterTransition 및 ExitTransition 함수 외에도 AnimatedContent는 slideIntoContainer 및 slideOutOfContainer를 제공합니다. 이 함수는 초기 콘텐츠의 크기와 AnimatedContent 콘텐츠의 대상 콘텐츠에 따라 슬라이드 거리를 계산하는 slideInHorizontally/Vertically 및 slideOutHorizontally/Vertically의 편리한 대안입니다.

 

SizeTransform 초기 콘텐츠와 대상 콘텐츠 사이에서 크기를 어떻게 애니메이션할지 정의합니다. 애니메이션을 만들 초기 크기와 대상 크기에 모두 액세스할 있습니다. 또한 애니메이션 중에 콘텐츠를 컴포넌트 크기에 맞게 잘라낼지 여부도 SizeTransform 통해 제어할 있습니다.

var expanded by remember { mutableStateOf(false) }
Surface(
    color = MaterialTheme.colorScheme.primary,
    onClick = { expanded = !expanded }
) {
    AnimatedContent(
        targetState = expanded,
        transitionSpec = {
            fadeIn(animationSpec = tween(150, 150)) with
                fadeOut(animationSpec = tween(150)) using
                SizeTransform { initialSize, targetSize ->
                    if (targetState) {
                        keyframes {
                            // Expand horizontally first.
                            IntSize(targetSize.width, initialSize.height) at 150
                            durationMillis = 300
                        }
                    } else {
                        keyframes {
                            // Shrink vertically first.
                            IntSize(initialSize.width, targetSize.height) at 150
                            durationMillis = 300
                        }
                    }
                }
        }
    ) { targetExpanded ->
        if (targetExpanded) {
            Expanded()
        } else {
            ContentIcon()
        }
    }
}

Animate child enter and exit transitions

AnimatedVisibility 마찬가지로 animateEnterExit 수정자는 AnimatedContent 콘텐츠 람다 내부에서 사용할 있습니다. 이를 사용하여 직접 또는 간접 자식 각각에 EnterAnimation ExitAnimation 개별적으로 적용할 있습니다.

Add custom animation

AnimatedVisibility와 마찬가지로 전환 필드는 AnimatedContent의 콘텐츠 람다 내에서 사용할 수 있습니다. 이 필드를 사용하여 AnimatedContent 전환과 동시에 실행되는 사용자 지정 애니메이션 효과를 만들 수 있습니다. 자세한 내용은 업데이트 트랜지션을 참조하세요.
 

Animate between two layouts with Crossfade

Crossfade 애니메이션은 두 레이아웃 사이에 Crossfade 애니메이션을 적용합니다. 현재 매개변수에 전달된 값을 토글하면 콘텐츠가 Crossfade 애니메이션으로 전환됩니다.
var currentPage by remember { mutableStateOf("A") }
Crossfade(targetState = currentPage) { screen ->
    when (screen) {
        "A" -> Text("Page A")
        "B" -> Text("Page B")
    }
}

Animate composable size changes with animateContentSize

var message by remember { mutableStateOf("Hello") }
Box(
    modifier = Modifier.background(Color.Blue).animateContentSize()
) { Text(text = message) }