0Pricing
Android Academy · บทเรียน

พื้นฐาน 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. เหตุใดแอนิเมชันจึงสำคัญ
  2. พื้นฐาน animate*AsState
  3. AnimatedVisibility และการเปลี่ยนผ่าน
  4. แอนิเมชันท่าทางและสปริง
← กลับไปที่ Android Academy