พื้นฐาน animate*AsState
สร้างแอนิเมชันให้ค่าทีละค่าอย่างราบรื่น
พื้นฐาน animate*AsState เป็นบทเรียน Android Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Android Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน
ทำแอนิเมชันให้ค่าหนึ่งค่า
วิธีที่ง่ายที่สุดในการทำแอนิเมชันใน Compose คือตระกูล animate*AsState คุณส่งค่าเป้าหมายให้ แล้ว API จะคืนค่า State ที่ค่อย ๆ เปลี่ยนจากค่าปัจจุบันไปยังค่าเป้าหมายอย่างราบรื่นทุกครั้งที่ค่าเป้าหมายเปลี่ยน
มีรูปแบบสำหรับชนิดค่าที่ใช้กันทั่วไปแต่ละชนิด ได้แก่ animateFloatAsState, animateDpAsState, animateColorAsState, animateOffsetAsState และอื่น ๆ
animateFloatAsState
animateFloatAsState ทำแอนิเมชันให้ค่า Float หนึ่งค่า การใช้งานที่พบบ่อยคือความทึบแสง (อัลฟา) เมื่อ visible เปลี่ยนค่า อัลฟาที่คืนมาจะค่อย ๆ เปลี่ยนระหว่าง 0f กับ 1f
สังเกตคีย์เวิร์ด by: คีย์เวิร์ดนี้ช่วยให้คุณอ่านค่า State<Float> ที่กำลังทำแอนิเมชันได้โดยตรงในรูปค่า Float ธรรมดา
@Composable
fun FadingLabel(visible: Boolean) {
val alpha by animateFloatAsState(
targetValue = if (visible) 1f else 0f,
label = "alpha"
)
Text(
"Hello",
modifier = Modifier.graphicsLayer { this.alpha = alpha }
)
}animateDpAsState
ขนาดและตำแหน่งเลื่อนของส่วนติดต่อผู้ใช้ใช้ Dp ดังนั้นให้เลือกใช้ animateDpAsState เพื่อทำแอนิเมชันให้ระยะขอบภายใน ขนาด หรือตำแหน่ง
ในตัวอย่างนี้ กล่องจะขยายจาก 80dp เป็น 160dp เมื่อสลับค่า เนื่องจากเราส่งค่า Dp ที่กำลังทำแอนิเมชันเข้า size() กล่องจึงปรับขนาดอย่างราบรื่น
@Composable
fun GrowingBox(big: Boolean) {
val size by animateDpAsState(
targetValue = if (big) 160.dp else 80.dp,
label = "size"
)
Box(
Modifier
.size(size)
.background(Color.Blue)
)
}animateColorAsState
หากต้องการทำแอนิเมชันให้สี ให้ใช้ animateColorAsState API จะคำนวณค่าระหว่างสีในปริภูมิสี ทำให้การเปลี่ยนแปลงดูราบรื่นและเป็นธรรมชาติ แทนที่จะกะพริบผ่านเฉดสีแปลก ๆ ระหว่างทาง
ในตัวอย่างนี้ จุดแสดงสถานะจะเปลี่ยนแอนิเมชันระหว่างสีแดงกับสีเขียวตามค่าบูลีน
@Composable
fun StatusDot(online: Boolean) {
val color by animateColorAsState(
targetValue = if (online) Color(0xFF4CAF50) else Color(0xFFF44336),
label = "status-color"
)
Box(
Modifier
.size(16.dp)
.clip(CircleShape)
.background(color)
)
}ปรับแต่งด้วย animationSpec
โดยค่าเริ่มต้น ตัวช่วยเหล่านี้ใช้สปริงที่นุ่มนวล คุณสามารถส่ง animationSpec เพื่อควบคุมจังหวะเวลาได้ ใช้ tween หากต้องการกำหนดระยะเวลาตายตัวพร้อมเส้นโค้งการเร่ง
แผงนี้จะเลื่อนเข้ามาในเวลา 400 มิลลิวินาที โดยใช้เส้นโค้งที่เร่งความเร็วแล้วค่อยชะลออย่างราบรื่น
@Composable
fun SlidingPanel(open: Boolean) {
val offset by animateDpAsState(
targetValue = if (open) 0.dp else 250.dp,
animationSpec = tween(
durationMillis = 400,
easing = FastOutSlowInEasing
),
label = "offset"
)
Box(Modifier.offset(x = offset)) { /* content */ }
}เส้นโค้งการเร่ง
เส้นโค้งการเร่งกำหนดลักษณะการเร่งและการชะลอของแอนิเมชัน Compose มีเส้นโค้งให้เลือกหลายแบบ:
LinearEasing- ความเร็วคงที่ ให้ความรู้สึกเหมือนกลไกFastOutSlowInEasing- ค่าเริ่มต้นของ Material เริ่มเร็วและจบอย่างนุ่มนวลLinearOutSlowInEasing- สำหรับองค์ประกอบที่เข้าสู่หน้าจอFastOutLinearInEasing- สำหรับองค์ประกอบที่ออกจากหน้าจอ
การเลือกเส้นโค้งการเร่งที่เหมาะสมทำให้การเคลื่อนไหวดูตั้งใจออกแบบ แทนที่จะดูเหมือนหุ่นยนต์
val progress by animateFloatAsState(
targetValue = if (done) 1f else 0f,
animationSpec = tween(500, easing = LinearOutSlowInEasing),
label = "progress"
)ข้อกำหนดของสปริง
แทนที่จะกำหนดระยะเวลาตายตัว คุณสามารถใช้ สปริง ซึ่งให้ความรู้สึกเหมือนวัตถุจริงและเป็นธรรมชาติ สปริงกำหนดด้วย dampingRatio (ความเด้ง) และ stiffness (ความเร็ว)
สปริงมีประโยชน์มาก เพราะจะปรับตัวอย่างราบรื่นแม้ว่าค่าเป้าหมายจะเปลี่ยนระหว่างที่แอนิเมชันกำลังทำงาน
val scale by animateFloatAsState(
targetValue = if (active) 1.2f else 1f,
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow
),
label = "scale"
)ตอบสนองเมื่อเสร็จสิ้น
บางครั้งคุณต้องทำบางอย่างเมื่อแอนิเมชันเสร็จสิ้น เช่น เรียกฟังก์ชันย้อนกลับหนึ่งครั้งเมื่อค่าหนึ่งไปถึงเป้าหมาย animate*AsState รองรับ finishedListener สำหรับกรณีนี้โดยเฉพาะ
val alpha by animateFloatAsState(
targetValue = if (gone) 0f else 1f,
label = "alpha",
finishedListener = { finalValue ->
if (finalValue == 0f) onFullyHidden()
}
)ทำแอนิเมชันให้หลายคุณสมบัติ
คุณสามารถรวมการเรียกใช้ animate*AsState หลายครั้งเพื่อทำแอนิเมชันให้คุณสมบัติมากกว่าหนึ่งรายการพร้อมกัน แต่ละรายการจะติดตามค่าของตนเอง และเมื่อทำงานร่วมกันจะสร้างเอฟเฟกต์ที่น่าสนใจยิ่งขึ้น
ในตัวอย่างนี้ ชิปจะย่อขยายและเปลี่ยนสีเมื่อถูกเลือก
@Composable
fun SelectableChip(selected: Boolean, text: String) {
val scale by animateFloatAsState(if (selected) 1.1f else 1f, label = "s")
val bg by animateColorAsState(
if (selected) Color(0xFF3F51B5) else Color.LightGray,
label = "bg"
)
Box(
Modifier
.graphicsLayer { scaleX = scale; scaleY = scale }
.clip(RoundedCornerShape(16.dp))
.background(bg)
.padding(horizontal = 12.dp, vertical = 6.dp)
) { Text(text) }
}สปริงใน Kotlin ล้วน
เพื่อสร้างความเข้าใจว่าสปริง "ทำงาน" อย่างไร ต่อไปนี้คือการจำลองขนาดเล็กด้วย Kotlin ล้วน โดยจะขยับค่าเข้าใกล้เป้าหมายในแต่ละขั้นพร้อมแรงหน่วง คล้ายกับที่สปริงของ Compose ค่อย ๆ เข้าสู่ค่าเป้าหมายตลอดหลายเฟรม
fun main() {
var value = 0f
val target = 100f
var velocity = 0f
val stiffness = 0.1f
val damping = 0.6f
repeat(6) { step ->
val force = (target - value) * stiffness
velocity = (velocity + force) * damping
value += velocity
println("step $step -> ${"%.1f".format(value)}")
}
}ทำแอนิเมชันให้ Int และ Offset
ตระกูลนี้รองรับมากกว่าค่าจำนวนทศนิยมและสี ใช้ animateIntAsState กับค่าจำนวนเต็ม เช่น เป้าหมายของจำนวนป้ายแจ้งเตือน และใช้ animateOffsetAsState หรือ animateIntOffsetAsState เพื่อทำแอนิเมชันให้ตำแหน่งสองมิติด้วยการเรียกใช้เพียงครั้งเดียว
ในตัวอย่างนี้ ชิปจะเลื่อนในแนวทแยงด้วยการทำแอนิเมชันให้ค่า IntOffset
@Composable
fun SlidingChip(moved: Boolean) {
val pos by animateIntOffsetAsState(
targetValue = if (moved) IntOffset(120, 60) else IntOffset.Zero,
label = "pos"
)
Box(
Modifier
.offset { pos }
.size(40.dp)
.background(Color.Magenta)
)
}ตรวจสอบความเข้าใจ
คุณต้องการทำแอนิเมชันให้ความกว้างของกล่อง ซึ่งวัดด้วย Dp เปลี่ยนอย่างราบรื่นเมื่อค่าบูลีนเปลี่ยน ควรใช้ API ใด
ทบทวน: animate*AsState
ตระกูล animate*AsState เป็นตัวเลือกหลักสำหรับทำแอนิเมชันให้ค่าหนึ่งค่า:
- เลือกรูปแบบตามชนิดข้อมูล:
animateFloatAsState,animateDpAsState,animateColorAsStateและอื่น ๆ - กำหนด
targetValueแล้วผลลัพธ์จะทำแอนิเมชันเข้าใกล้ค่านี้ทุกครั้งที่มีการเปลี่ยนแปลง - ปรับการเคลื่อนไหวด้วย
animationSpecโดยใช้tweenร่วมกับเส้นโค้งการเร่ง หรือใช้spring - รวมหลายรายการเพื่อทำแอนิเมชันให้หลายคุณสมบัติพร้อมกัน
- ใช้
finishedListenerเพื่อตอบสนองเมื่อแอนิเมชันเสร็จสิ้น
ถัดไป: ทำแอนิเมชันให้เนื้อหาปรากฏและหายไปด้วย AnimatedVisibility และการเปลี่ยนสถานะ
คำถามที่พบบ่อย
บทเรียน “พื้นฐาน animate*AsState” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “พื้นฐาน animate*AsState” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Android Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Android Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “พื้นฐาน animate*AsState”
สร้างแอนิเมชันให้ค่าทีละค่าอย่างราบรื่น คุณปฏิบัติ Android Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Android Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Android Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “พื้นฐาน animate*AsState” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Android Academy นี้ได้ไหม
ได้ บทเรียน Android Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เหตุใดแอนิเมชันจึงสำคัญ
- พื้นฐาน animate*AsState
- AnimatedVisibility และการเปลี่ยนผ่าน
- แอนิเมชันท่าทางและสปริง