animate*AsState関数は制御する値のタイプにより、数種類が準備されています。
どの関数も、animateValueAsStateが原型のラッパー関数であり、動作は同じです。
ここでは、各々の関数について、サンプルを示します。
また、animateValueAsStateのサンプルは、独自の関数を作る方法を紹介しています。
※環境:Android Studio Iguana | 2023.2.1
Kotlin 1.9.0
Compose Compiler 1.5.1
androidx.compose.animation:* 1.5.0
目次
関数の種類
animate*AsState関数は制御する値のタイプにより、次のような種類が準備されています。
アニメーション関数 | タイプ | コメント |
---|---|---|
animateFloatAsState | Float | |
animateIntAsState | Int | |
animateDpAsState | Dp | |
animateOffsetAsState | Offset | x、yはFloat型 x、yは独立して制御可能 |
animateIntOffsetAsState | IntOffset | x、yはInt型 x、yは独立して制御可能 |
animateSizeAsState | Size | width、heightはFloat型 width、heightは独立して制御可能 |
animateIntSizeAsState | IntSize | width、heightはInt型 width、heightは独立して制御可能 |
animateColorAsState | Color | a、r、g、bは独立して制御可能 |
animateRectAsState | Rect | left、top、right、bottomはFloat型 left、top、right、bottomは独立して制御可能 |
animateValueAsState | Value | 上記9つの原型になる関数 |
この中で、animateValueAsStateは原型になる関数です。他の関数はanimateValueAsStateのラッパー関数になります。
例:animateFloat/IntAsState
private val StartAlphaF = 0.0f private val EndAlphaF = 1.0f @Preview_mdpi @Composable private fun AnimateFloatAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 240.dp) .background(color = Color(0xFFF0F0FF)), contentAlignment = Alignment.Center ) { val _toggle = remember { mutableStateOf(false) } val _alpha = animateFloatAsState( targetValue = if(_toggle.value) EndAlphaF else StartAlphaF, animationSpec = tween(durationMillis = 1000) ) Image( painter = painterResource(R.drawable.leaf1), contentDescription = null, modifier = Modifier .background(color = Color.LightGray) .alpha(_alpha.value) .clickable { _toggle.value = !_toggle.value } ) } }
private val StartAlphaI = 0x00 private val EndAlphaI = 0xff @Preview_mdpi @Composable private fun AnimateIntAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 240.dp) .background(color = Color(0xFFF0F0FF)), contentAlignment = Alignment.Center ) { val _toggle = remember { mutableStateOf(false) } val _alpha = animateIntAsState( targetValue = if(_toggle.value) EndAlphaI else StartAlphaI, animationSpec = tween(durationMillis = 1000) ) Image( painter = painterResource(R.drawable.leaf1), contentDescription = null, modifier = Modifier .background(color = Color.LightGray) .alpha(_alpha.value.toFloat() / 255.0f) .clickable { _toggle.value = !_toggle.value } ) } }
例:animateDpAsState
private val StartX = 20.dp private val EndX = 260.dp @Preview_mdpi @Composable private fun AnimateDpAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 100.dp) .background(color = Color(0xFFF0F0FF)), contentAlignment = Alignment.CenterStart ) { val _toggle = remember { mutableStateOf(false) } val _posX = animateDpAsState( targetValue = if(_toggle.value) EndX else StartX, animationSpec = tween(durationMillis = 1000) ) Image( painter = painterResource(R.drawable.baseline_toys_black_36), contentDescription = null, modifier = Modifier .size(36.dp) .offset(x = _posX.value) .clickable { _toggle.value = !_toggle.value } ) } }
※「関数の動作」で掲載したサンプルと同じ
例:animateOffset/IntOffsetAsState
private val StartOffset = Offset(20.0f, 20.0f) // Floatで表したDp値 private val EndOffset = Offset(260.0f, 180.0f) // Floatで表したDp値 @Preview_mdpi @Composable private fun AnimateOffsetAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 240.dp) .background(color = Color(0xFFF0F0FF)) ) { val _toggle = remember { mutableStateOf(false) } val _offset = animateOffsetAsState( targetValue = if(_toggle.value) EndOffset else StartOffset, animationSpec = tween(durationMillis = 1000) ) Image( painter = painterResource(R.drawable.baseline_toys_black_36), contentDescription = null, modifier = Modifier .size(36.dp) // ↓↓ offsetはDpを欲する ↓↓ .offset(x = _offset.value.x.dp, y = _offset.value.y.dp) .clickable { _toggle.value = !_toggle.value } ) } }
private val StartIntOffset = IntOffset(20, 20) // Intで表したDp値 private val EndIntOffset = IntOffset(260, 180) // Intで表したDp値 @Preview_mdpi @Composable private fun AnimateIntOffsetAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 240.dp) .background(color = Color(0xFFF0F0FF)) ) { val _toggle = remember { mutableStateOf(false) } val _offset = animateIntOffsetAsState( targetValue = if(_toggle.value) EndIntOffset else StartIntOffset, animationSpec = tween(durationMillis = 1000) ) Image( painter = painterResource(R.drawable.baseline_toys_black_36), contentDescription = null, modifier = Modifier .size(36.dp) // ↓↓ offsetはPxを欲する ↓↓ .offset { _offset.value * density } .clickable { _toggle.value = !_toggle.value } ) } }
例:animateSize/IntSizeAsState
private val StartSize = Size(50.0f, 210.0f) // Floatで表したDp値 private val EndSize = Size(200.0f, 150.0f) // Floatで表したDp値 @Preview_mdpi @Composable private fun AnimateSizeAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 240.dp) .background(color = Color(0xFFF0F0FF)), contentAlignment = Alignment.Center ) { val _toggle = remember { mutableStateOf(false) } val _size = animateSizeAsState( targetValue = if(_toggle.value) EndSize else StartSize, animationSpec = tween(durationMillis = 1000) ) Image( painter = painterResource(R.drawable.leaf2), contentDescription = null, contentScale = ContentScale.FillBounds, modifier = Modifier .size(width = _size.value.width.dp, height = _size.value.height.dp) .clickable { _toggle.value = !_toggle.value } ) } }
private val StartIntSize = IntSize(50, 210) // Intで表したDp値 private val EndIntSize = IntSize(200, 150) // Intで表したDp値 @Preview_mdpi @Composable private fun AnimateIntSizeAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 240.dp) .background(color = Color(0xFFF0F0FF)), contentAlignment = Alignment.Center ) { val _toggle = remember { mutableStateOf(false) } val _size = animateIntSizeAsState( targetValue = if(_toggle.value) EndIntSize else StartIntSize, animationSpec = tween(durationMillis = 1000) ) Image( painter = painterResource(R.drawable.leaf2), contentDescription = null, contentScale = ContentScale.FillBounds, modifier = Modifier .size(width = _size.value.width.dp, height = _size.value.height.dp) .clickable { _toggle.value = !_toggle.value } ) } }
例:animateColorAsState
private val StartColor = Color(0xffff0040) private val EndColor = Color(0xff00ffc0) @Preview_mdpi @Composable private fun AnimateColorAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 240.dp) .background(color = Color(0xFFF0F0FF)), contentAlignment = Alignment.Center ) { val _toggle = remember { mutableStateOf(false) } val _color = animateColorAsState( targetValue = if(_toggle.value) EndColor else StartColor, animationSpec = tween(durationMillis = 1000) ) Image( painter = painterResource(R.drawable.leaf1), contentDescription = null, modifier = Modifier .background(color = _color.value) .scale(0.8f) .clickable { _toggle.value = !_toggle.value } ) } }
例:animateRectAsState
private val StartRect = Rect( // Floatで表したDp値 Offset(x = 10.0f, y = 10.0f), Size(50.0f, 100.0f)) private val EndRect = Rect( // Floatで表したDp値 Offset(x = 170.0f, y = 150.0f), Size(100.0f, 50.0f)) @Preview_mdpi @Composable private fun AnimateRectAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 240.dp) .background(color = Color(0xFFF0F0FF)), contentAlignment = Alignment.Center ) { val _toggle = remember { mutableStateOf(false) } val _rect = animateRectAsState( targetValue = if(_toggle.value) EndRect else StartRect, animationSpec = tween(durationMillis = 1000) ) Canvas( modifier = Modifier .size(280.dp, 210.dp) .background(color = Color.LightGray) .clickable { _toggle.value = !_toggle.value } ) { drawOval( color = Color.Red, topLeft = _rect.value.topLeft * density, // Dp->Px変換が必要 size = _rect.value.size * density) // Dp->Px変換が必要 } } }
例:animateValueAsState
animateValueAsStateは原型になる関数です。他の関数はanimateValueAsStateのラッパー関数になります。
他の関数と同様にVectorConverterを定義すれば、独自のanimateXXXAsState関数が作成できます。
以下は、3軸(X,Y,Z)の回転を行うRoataeXYZ.VectorConverterの例です。
data class RotateXYZ(val rX: Int, val rY: Int, val rZ: Int) { companion object } private val RotateXYZToVector: TwoWayConverter<RotateXYZ, AnimationVector3D> = TwoWayConverter( convertToVector = { AnimationVector3D(it.rX.toFloat(), it.rY.toFloat(), it.rZ.toFloat()) }, convertFromVector = { RotateXYZ(it.v1.roundToInt(), it.v2.roundToInt(), it.v3.roundToInt()) } ) val RotateXYZ.Companion.VectorConverter: TwoWayConverter<RotateXYZ, AnimationVector3D> get() = RotateXYZToVector
制御する値の個数(1/2/3/4個)により、アニメエンジン(AnimationVector1D/2D/3D/4D)を切り替えて使用します。
※例はタイプの変換箇所を明確するために、あえてrX/rY/rZをInt型で作成しています。Floatにすれば、toFloatとroundToIntは不要です。
private val StartRotate = RotateXYZ(rX = 0, rY = 0, rZ = 0) private val EndRotate = RotateXYZ(rX = 360, rY = 360, rZ = 360) @Preview_mdpi @Composable private fun AnimateValueAsStateSample() { Box( modifier = Modifier .size(width = 320.dp, height = 240.dp) .background(color = Color(0xFFF0F0FF)), contentAlignment = Alignment.Center ) { val _toggle = remember { mutableStateOf(false) } val _rotate = animateValueAsState( targetValue = if(_toggle.value) EndRotate else StartRotate, animationSpec = tween(durationMillis = 2000), typeConverter = RotateXYZ.VectorConverter ) Image( painter = painterResource(R.drawable.bike), contentDescription = null, modifier = Modifier .scale(0.7f) .clickable { _toggle.value = !_toggle.value } .graphicsLayer { rotationX = _rotate.value.rX.toFloat() rotationY = _rotate.value.rY.toFloat() rotationZ = _rotate.value.rZ.toFloat() } ) } }
関連記事: