🐻‍❄️

Jetpack Compose の Animated Visibility について深堀りする

2021/11/12に公開

はじめに

  • AnimatedVisibility は View の Visibility 変化させるアニメーション
  • AnimatedVisibility は特に動きのある表示・非表示を単一の View に対して実現したいときに利用する
  • AnimatedVisibility では引数に与える Editable もしくは MutableTransitionState を変化させることでアニメーションを動作させる

demo.gif

Editable(Boolean) でアニメーションを動作させる

  • Editable(Boolean) を remember で定義し変化させる
  • Editable(Boolean) を変化させると、それに応じてアニメーションが動作する

Jul-23-2021 14-42-32.gif

@ExperimentalAnimationApi
@Composable
fun AnimatedVisibilitySample() {
    var editable by remember { mutableStateOf(true) }

    Column(modifier = Modifier.padding(8.dp)) {
        Text(
            text = "AnimatedVisibility",
            style = MaterialTheme.typography.h6
        )

        AnimatedVisibility(visible = editable) {
            Surface(
                color = Color.Yellow,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(100.dp)
                    .align(Alignment.CenterHorizontally)
                    .padding(8.dp)
            ) {}
        }

        Button(
            onClick = { editable = !editable },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text(text = "Toggle")
        }
    }
}

MutableTransitionState でアニメーションを動作させる

  • MutableTransitionState を remember で定義する。
  • MutableTransitionState を変化させると、それに応じてアニメーションが動作する
  • MutableTransitionState には現在の表示状態を表す currentState と現在のアニメーション状況を表す isIdle が含まれる
  • そのため currentState と isIdle を組み合わせると表示済み・表示中・非表示・非表示中などの状態を識別できる

Jul-23-2021 14-42-37.gif

@ExperimentalAnimationApi
@Composable
fun AnimatedVisibilityStateSample() {
    val state = remember {
        MutableTransitionState(false).apply {
            targetState = true
        }
    }

    Column(modifier = Modifier.padding(8.dp)) {
        Text(
            text = "AnimatedVisibilityState",
            style = MaterialTheme.typography.h6
        )

        AnimatedVisibility(visibleState = state) {
            Surface(
                color = Color.Yellow,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(100.dp)
                    .align(Alignment.CenterHorizontally)
                    .padding(8.dp)
            ) {
                Text(
                    text = state.getAnimationState().toString()
                )
            }
        }

        Button(
            onClick = { state.targetState = !state.currentState },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text(text = "Toggle")
        }
    }
}
// 今回はこのような拡張関数を用意してみた、すると簡単にアニメーション状態が取得できる
enum class AnimState {
    VISIBLE,
    INVISIBLE,
    APPEARING,
    DISAPPEARING
}

fun MutableTransitionState<Boolean>.getAnimationState(): AnimState {
    return when {
        this.isIdle && this.currentState -> AnimState.VISIBLE
        !this.isIdle && this.currentState -> AnimState.DISAPPEARING
        this.isIdle && !this.currentState -> AnimState.INVISIBLE
        else -> AnimState.APPEARING
    }
}

表示・非表示時のアニメーションを追加できる

  • AnimatedVisibility には enter と exit という引数が用意されている
  • ここに fadeIn や fadeOut のアニメーションを渡してやると簡単に Visibility が変化したときにアニメーションを追加できる

Jul-23-2021 14-42-41.gif

@ExperimentalAnimationApi
@Composable
fun AnimatedVisibilityEnterExitSample() {
    val state = remember {
        MutableTransitionState(false).apply {
            targetState = true
        }
    }

    Column(modifier = Modifier.padding(8.dp)) {
        Text(
            text = "AnimatedVisibilityState",
            style = MaterialTheme.typography.h6
        )

        AnimatedVisibility(
            visibleState = state,
            enter = fadeIn(),
            exit = fadeOut()
        ) {
            Surface(
                color = Color.Yellow,
                modifier = Modifier
                    .fillMaxWidth()
                    .height(100.dp)
                    .align(Alignment.CenterHorizontally)
                    .padding(8.dp)
            ) {
                Text(text = state.getAnimationState().toString())
            }
        }

        Button(
            onClick = { state.targetState = !state.currentState },
            modifier = Modifier.fillMaxWidth()
        ) {
            Text(text = "Toggle")
        }
    }
}

おわりに

  • AnimationVisibility では簡単に View の Visibility をアニメーションで切り替えられる
  • AnimationVisibility では動きのある表示・非表示を実現するのが得意

参考文献

Discussion