Animation in Jetpack Compose
แอนิเมชั่นเป็นพื้นฐานสำคัญในแอปพลิเคชันสมัยนี้ เพราะนอกจากความสวยงามและความทันสมัยแล้ว ก็เพื่อให้ผู้ใช้ได้รับประสบการณ์ที่ราบรื่นและเข้าใจได้ง่ายขึ้น โดย Jetpack Compose มี API แอนิเมชั่นต่างๆ diagram ด้านล่างนี้จะช่วยให้คุณตัดสินใจเลือกได้ตามความเหมาะสม
มาเริ่มกันที่ API แอนิเมชั่นที่ง่ายที่สุดตัวหนึ่งใน Compose: animate*AsState ควรใช้ API นี้เมื่อมีการเปลี่ยนแปลงสถานะ value สามารถเป็นได้ทั้ง Float, Color, Dp, Size .. แต่ถ้าคุณต้องการ animate ค่าสี api ที่ควรใช้ก็คือ
AnimateColorAsState
var isSwitch by remember { mutableStateOf(false) }
val backgroundColor by animateColorAsState(
if (isSwitch) Yellow200 else Purple200,
animationSpec = tween(2000)
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Box(
Modifier
.fillMaxWidth()
.fillMaxHeight(0.8f)
.background(backgroundColor)
)
Button(
colors = ButtonDefaults.buttonColors(backgroundColor = backgroundColor),
onClick = { isSwitch = !isSwitch },
modifier = Modifier
.padding(top = 10.dp)
) {
Text(text = "Change Color")
}
}
เป็นตัวอย่างการสลับสีพื้นหลังและสีปุ่มจากสีม่วงเป็นสีเหลือง สามารถใส่ animationSpec = tween(durationMillis) เข้าไปได้เพื่อให้เห็นเอฟเฟกต์ของแอนิเมชั่นชัดขึ้น
output:
animateContentSize
ทำให้การเปลี่ยนแปลงของขนาดเคลื่อนไหวได้โดยการใช้ animateContentSize
var isExpand by remember { mutableStateOf(false) }
val textContent = if (isExpand) title + description else title
ให้ค่า textContent โดยอิงจากค่าของ isExpand ที่เปลี่ยน state จากการ click
Image(
painter = painterResource(R.drawable.movie),
contentDescription = "movie",
modifier = Modifier
.size(400.dp, 250.dp)
)
Row(
modifier = Modifier
.background(Orange200)
.fillMaxWidth()
.padding(16.dp)
.animateContentSize(
animationSpec = tween(200)
)
.clickable {
isExpand = !isExpand
}
) {
Icon(
imageVector = Icons.Default.Favorite,
contentDescription = null
)
Spacer(modifier = Modifier.width(16.dp))
Text(
text = textContent,
style = MaterialTheme.typography.body1
)
}
Row จะเปลี่ยนขนาดเมื่อมีการเปลี่ยนแปลงเนื้อหา
output:
Repeating animation
การทำ animation แบบซ้ำโดยใช้ InfiniteTransition สามารถ create instance ของ InfiniteTransition ด้วย rememberInfiniteTransition และสามารถเพิ่ม child animations ด้วย animateColor, animatedFloat, หรือ animatedValue
val infiniteTransition = rememberInfiniteTransition()
val heartSize by infiniteTransition.animateFloat(
initialValue = 150.0f,
targetValue = 300.0f,
animationSpec = infiniteRepeatable(
animation = tween(1000),
repeatMode = RepeatMode.Reverse
)
)
Image(
painter = painterResource(R.drawable.icon_heart),
contentDescription = "icon heart",
modifier = Modifier.size(heartSize.dp),
alpha = alpha
)
ใน case นี้เราใช้ animateFloat เพื่อกำหนด size ให้กับรูปภาพโดยเริ่มที่ initialValue ที่ขนาดเล็ก และ targetValue ที่ขนาดใหญ่ขึ้น และ set animationSpec ให้ repeatMode เป็น Reverse โดยค่า default ของมันคือ Restart
val alpha by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = keyframes {
durationMillis = 1000
0.7f at 500
},
repeatMode = RepeatMode.Reverse
)
)
set alpha ให้กับรูปได้ด้วย โดยเริ่มที่ 0f ไปถึง 1f และมีการ set keyframes ให้ alpha 0.7f เมื่อ duration 500ms
output:
AnimatedVisibility
เป็นการใส่ animation ให้กับการ show และ hide โดยค่า default ของการโชว์ content คือเฟดเข้าและขยายออก การซ่อนคือการจางลงและย่อขนาด
AnimatedVisibility(
visible = isShow,
enter = slideInVertically(
animationSpec = tween(durationMillis = 100, easing = LinearOutSlowInEasing)
),
exit = slideOutVertically(
animationSpec = tween(durationMillis = 200, easing = FastOutLinearInEasing)
)
)
สามารถกำหนดค่า enter exit ได้ แต่ behavior ของ slideInVertically และ slideOutVertically เป็นการใช้ความสูงของ content เพียงครึ่งนึงเท่านั้น
output:
อ่านเพิ่มเติมเกี่ยวกับ EnterTransition และ ExitTransition click
AnimationSpec
การปรับแต่ง animation ด้วย พารามิเตอร์ animationSpec
- spring สร้าง animation ตามฟิสิกส์ ระหว่างค่าเริ่มต้นและค่าสิ้นสุด ใช้พารามิเตอร์ 2 ตัวนี้
dampingRatio -> เป็นตัวกำหนดความเด้งของสปริง ค่าเริ่มต้นคือ Spring.DampingRatioNoBouncy
stiffness -> กำหนดว่าสปริงควรเคลื่อนที่ไปสู่ค่าสิ้นสุดเร็วเพียงใด ค่าเริ่มต้นคือ Spring.StiffnessMedium
Button(onClick = { isClick = !isClick },
modifier = Modifier
.animateContentSize(
animationSpec = spring(
dampingRatio = Spring.DampingRatioHighBouncy,
stiffness = Spring.StiffnessLow
))
) {
Text(
text = text,
textAlign = TextAlign.Center
)
}
output:
- snap ใช้สำหรับทำให้เคลื่อนไหวจากค่าหนึ่งไปยังอีกค่าหนึ่งอย่างรวดเร็ว นอกจากนี้ เราสามารถตั้งค่า delay ระหว่างช่วงการเปลี่ยนภาพได้อีกด้วย
val alpha by animateFloatAsState(
targetValue = if (isAnimate) 1.0f else 0.5f,
animationSpec = snap(delayMillis = 300),
)Icon(
painter = painterResource(R.drawable.bin),
contentDescription = "bin",
modifier = Modifier
.size(300.dp)
.alpha(alpha = alpha)
)
output:
ทั้งหมดนี้ก็เป็นตัวอย่างการใช้ animation ใน jetpack compose บางส่วนเท่านั้น สำหรับใครที่สนใจอ่านข้อมูลเพิ่มเติมก็ตามนี้เลย
https://developer.android.com/jetpack/compose/animation