คำแนะนำโดยย่อเกี่ยวกับภาพเคลื่อนไหวใน Compose

Compose มีกลไกภาพเคลื่อนไหวในตัวมากมาย และอาจทำให้คุณสับสนเมื่อต้องเลือกใช้ ต่อไปนี้คือรายการกรณีการใช้งานภาพเคลื่อนไหวที่พบบ่อย ดูข้อมูลโดยละเอียดเพิ่มเติมเกี่ยวกับตัวเลือก API ต่างๆ ทั้งหมด ที่คุณใช้ได้ที่เอกสารประกอบเกี่ยวกับ Compose Animation ฉบับเต็ม

ทําให้คุณสมบัติที่ใช้ร่วมกันได้ทั่วไปเคลื่อนไหว

Compose มี API ที่สะดวกซึ่งช่วยให้คุณแก้ปัญหาเคสการใช้งานภาพเคลื่อนไหวทั่วไปได้หลายอย่าง ส่วนนี้จะแสดงวิธีสร้างภาพเคลื่อนไหวให้กับพร็อพเพอร์ตี้ทั่วไปของ Composable

ทำให้ปรากฏ / หายไป

Green composable แสดงและซ่อนตัวเอง
รูปที่ 1 การทำให้การปรากฏและหายไปของรายการในคอลัมน์เคลื่อนไหว

ใช้ AnimatedVisibility เพื่อซ่อนหรือแสดง Composable เด็กๆ ในAnimatedVisibility สามารถใช้ Modifier.animateEnterExit() สำหรับการเปลี่ยนฉากเข้าหรือออกของตนเองได้

var visible by remember {
    mutableStateOf(true)
}
// Animated visibility will eventually remove the item from the composition once the animation has finished.
AnimatedVisibility(visible) {
    // your composable here
    // ...
}

พารามิเตอร์เข้าและออกของ AnimatedVisibility ช่วยให้คุณกำหนดค่าลักษณะการทำงานของ Composable เมื่อปรากฏและหายไปได้ อ่านข้อมูลเพิ่มเติมได้ในเอกสารประกอบ ฉบับเต็ม

อีกตัวเลือกหนึ่งในการสร้างภาพเคลื่อนไหวให้การมองเห็นของ Composable คือการสร้างภาพเคลื่อนไหวให้ อัลฟ่าเมื่อเวลาผ่านไปโดยใช้ animateFloatAsState ดังนี้

var visible by remember {
    mutableStateOf(true)
}
val animatedAlpha by animateFloatAsState(
    targetValue = if (visible) 1.0f else 0f,
    label = "alpha"
)
Box(
    modifier = Modifier
        .size(200.dp)
        .graphicsLayer {
            alpha = animatedAlpha
        }
        .clip(RoundedCornerShape(8.dp))
        .background(colorGreen)
        .align(Alignment.TopCenter)
) {
}

อย่างไรก็ตาม การเปลี่ยนค่าอัลฟ่ามีข้อควรระวังคือ Composable จะยังคง อยู่ใน Composition และยังคงใช้พื้นที่ที่กำหนดไว้ ซึ่งอาจทำให้โปรแกรมอ่านหน้าจอและกลไกการช่วยเหลือพิเศษอื่นๆ ยังคงพิจารณารายการบนหน้าจอ ในทางกลับกัน AnimatedVisibility จะนำ รายการออกจากองค์ประกอบในที่สุด

การทำให้ค่าอัลฟ่าของ Composable เคลื่อนไหว
รูปที่ 2 การสร้างภาพเคลื่อนไหวของอัลฟ่าของ Composable

เปลี่ยนสีพื้นหลังแบบเคลื่อนไหว

สามารถสร้างร่วมกันได้โดยมีการเปลี่ยนสีพื้นหลังเมื่อเวลาผ่านไปเป็นภาพเคลื่อนไหว ซึ่งสีจะค่อยๆ จางลงเป็นสีอื่น
รูปที่ 3 สร้างภาพเคลื่อนไหวให้กับสีพื้นหลังของ Composable

val animatedColor by animateColorAsState(
    if (animateBackgroundColor) colorGreen else colorBlue,
    label = "color"
)
Column(
    modifier = Modifier.drawBehind {
        drawRect(animatedColor)
    }
) {
    // your composable here
}

ตัวเลือกนี้มีประสิทธิภาพมากกว่าการใช้ Modifier.background() Modifier.background() ใช้ได้กับการตั้งค่าสีแบบครั้งเดียว แต่เมื่อ เคลื่อนไหวสีเมื่อเวลาผ่านไป การตั้งค่านี้อาจทำให้เกิดการคอมโพสิตใหม่มากกว่า ที่จำเป็น

หากต้องการทำให้สีพื้นหลังเคลื่อนไหวอย่างต่อเนื่อง ให้ดูส่วนการทำซ้ำภาพเคลื่อนไหว

เคลื่อนไหวขนาดของ Composable

Green composable animating its size change smoothly.
รูปที่ 4 Composable ที่เคลื่อนไหวอย่างราบรื่นระหว่างขนาดเล็กและขนาดใหญ่

Compose ช่วยให้คุณเคลื่อนไหวขนาดของ Composable ได้หลายวิธี ใช้ animateContentSize() สำหรับภาพเคลื่อนไหวระหว่างการเปลี่ยนแปลงขนาดที่ประกอบได้

ตัวอย่างเช่น หากคุณมีกล่องที่มีข้อความซึ่งขยายจาก 1 บรรทัดเป็นหลายบรรทัดได้ คุณสามารถใช้ Modifier.animateContentSize() เพื่อให้การเปลี่ยนผ่านราบรื่นยิ่งขึ้นได้โดยทำดังนี้

var expanded by remember { mutableStateOf(false) }
Box(
    modifier = Modifier
        .background(colorBlue)
        .animateContentSize()
        .height(if (expanded) 400.dp else 200.dp)
        .fillMaxWidth()
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null
        ) {
            expanded = !expanded
        }

) {
}

คุณยังใช้ AnimatedContent ร่วมกับ SizeTransform เพื่ออธิบาย วิธีเปลี่ยนขนาดได้ด้วย

ทําให้ตําแหน่งของ Composable เคลื่อนไหว

Composable สีเขียวเคลื่อนไหวลงและไปทางขวาอย่างราบรื่น
รูปที่ 5 การเคลื่อนที่ที่ประกอบได้โดยออฟเซ็ต

หากต้องการเคลื่อนไหวตำแหน่งของ Composable ให้ใช้ Modifier.offset{ } ร่วมกับ animateIntOffsetAsState()

var moved by remember { mutableStateOf(false) }
val pxToMove = with(LocalDensity.current) {
    100.dp.toPx().roundToInt()
}
val offset by animateIntOffsetAsState(
    targetValue = if (moved) {
        IntOffset(pxToMove, pxToMove)
    } else {
        IntOffset.Zero
    },
    label = "offset"
)

Box(
    modifier = Modifier
        .offset {
            offset
        }
        .background(colorBlue)
        .size(100.dp)
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null
        ) {
            moved = !moved
        }
)

เท่านั้น

หากต้องการให้มั่นใจว่าระบบจะไม่วาด Composable ทับหรือใต้ Composable อื่นเมื่อเคลื่อนไหวตำแหน่งหรือขนาด ให้ใช้ Modifier.layout{ } ตัวแก้ไขนี้ จะส่งต่อการเปลี่ยนแปลงขนาดและตำแหน่งไปยังองค์ประกอบหลัก ซึ่งจะส่งผลต่อ องค์ประกอบย่อยอื่นๆ

ตัวอย่างเช่น หากคุณกำลังย้าย Box ภายใน Column และเด็กคนอื่นๆ ต้องย้ายตามเมื่อ Box เคลื่อนที่ ให้ใส่ข้อมูลออฟเซ็ตพร้อมกับ Modifier.layout{ } ดังนี้

var toggled by remember {
    mutableStateOf(false)
}
val interactionSource = remember {
    MutableInteractionSource()
}
Column(
    modifier = Modifier
        .padding(16.dp)
        .fillMaxSize()
        .clickable(indication = null, interactionSource = interactionSource) {
            toggled = !toggled
        }
) {
    val offsetTarget = if (toggled) {
        IntOffset(150, 150)
    } else {
        IntOffset.Zero
    }
    val offset = animateIntOffsetAsState(
        targetValue = offsetTarget, label = "offset"
    )
    Box(
        modifier = Modifier
            .size(100.dp)
            .background(colorBlue)
    )
    Box(
        modifier = Modifier
            .layout { measurable, constraints ->
                val offsetValue = if (isLookingAhead) offsetTarget else offset.value
                val placeable = measurable.measure(constraints)
                layout(placeable.width + offsetValue.x, placeable.height + offsetValue.y) {
                    placeable.placeRelative(offsetValue)
                }
            }
            .size(100.dp)
            .background(colorGreen)
    )
    Box(
        modifier = Modifier
            .size(100.dp)
            .background(colorBlue)
    )
}

กล่อง 2 กล่อง โดยกล่องที่ 2 จะเคลื่อนไหวตำแหน่ง X,Y และกล่องที่ 3 จะตอบสนองด้วยการเลื่อนตัวเองตามจำนวน Y ด้วย
รูปที่ 6 การสร้างภาพเคลื่อนไหวด้วย Modifier.layout{ }

สร้างภาพเคลื่อนไหวของระยะขอบของ Composable

Composable สีเขียวมีขนาดเล็กลงและใหญ่ขึ้นเมื่อคลิก โดยมีการเคลื่อนไหวของระยะขอบ
รูปที่ 7 สามารถใช้ร่วมกับการเคลื่อนไหวของระยะห่างจากขอบ

หากต้องการสร้างภาพเคลื่อนไหวให้กับระยะขอบของ Composable ให้ใช้ animateDpAsState ร่วมกับ Modifier.padding() ดังนี้

var toggled by remember {
    mutableStateOf(false)
}
val animatedPadding by animateDpAsState(
    if (toggled) {
        0.dp
    } else {
        20.dp
    },
    label = "padding"
)
Box(
    modifier = Modifier
        .aspectRatio(1f)
        .fillMaxSize()
        .padding(animatedPadding)
        .background(Color(0xff53D9A1))
        .clickable(
            interactionSource = remember { MutableInteractionSource() },
            indication = null
        ) {
            toggled = !toggled
        }
)

ทําให้ระดับความสูงของ Composable เคลื่อนไหว

รูปที่ 8 การยกระดับของ Composable ที่เคลื่อนไหวเมื่อคลิก

หากต้องการเคลื่อนไหวระดับความสูงของ Composable ให้ใช้ animateDpAsState ร่วมกับ Modifier.graphicsLayer{ } สำหรับการเปลี่ยนแปลงระดับความสูงแบบครั้งเดียว ให้ใช้ Modifier.shadow() หากคุณกำลังสร้างภาพเคลื่อนไหวของเงา การใช้ตัวแก้ไข Modifier.graphicsLayer{ } เป็นตัวเลือกที่มีประสิทธิภาพมากกว่า

val mutableInteractionSource = remember {
    MutableInteractionSource()
}
val pressed = mutableInteractionSource.collectIsPressedAsState()
val elevation = animateDpAsState(
    targetValue = if (pressed.value) {
        32.dp
    } else {
        8.dp
    },
    label = "elevation"
)
Box(
    modifier = Modifier
        .size(100.dp)
        .align(Alignment.Center)
        .graphicsLayer {
            this.shadowElevation = elevation.value.toPx()
        }
        .clickable(interactionSource = mutableInteractionSource, indication = null) {
        }
        .background(colorGreen)
) {
}

หรือจะใช้ Card ที่ประกอบได้ และตั้งค่าพร็อพเพอร์ตี้ยกระดับเป็นค่าต่างๆ ตามสถานะก็ได้

ทำให้การปรับขนาด การเปลี่ยนตำแหน่ง หรือการหมุนข้อความเคลื่อนไหว

ข้อความที่ใช้ได้กับ Composable ที่เขียนว่า Hello ซึ่งเคลื่อนไหวระหว่างขนาดเล็กและใหญ่
รูปที่ 9 ข้อความเคลื่อนไหวอย่างราบรื่นระหว่าง 2 ขนาด

เมื่อเคลื่อนไหวการปรับขนาด การแปล หรือการหมุนของข้อความ ให้ตั้งค่าพารามิเตอร์ textMotion ใน TextStyle เป็น TextMotion.Animated เพื่อให้การเปลี่ยนภาพระหว่างภาพเคลื่อนไหวของข้อความราบรื่นยิ่งขึ้น ใช้ Modifier.graphicsLayer{ } เพื่อแปล หมุน หรือปรับขนาดข้อความ

val infiniteTransition = rememberInfiniteTransition(label = "infinite transition")
val scale by infiniteTransition.animateFloat(
    initialValue = 1f,
    targetValue = 8f,
    animationSpec = infiniteRepeatable(tween(1000), RepeatMode.Reverse),
    label = "scale"
)
Box(modifier = Modifier.fillMaxSize()) {
    Text(
        text = "Hello",
        modifier = Modifier
            .graphicsLayer {
                scaleX = scale
                scaleY = scale
                transformOrigin = TransformOrigin.Center
            }
            .align(Alignment.Center),
        // Text composable does not take TextMotion as a parameter.
        // Provide it via style argument but make sure that we are copying from current theme
        style = LocalTextStyle.current.copy(textMotion = TextMotion.Animated)
    )
}

สีข้อความเคลื่อนไหว

คำว่า "Hello Compose" มีการเคลื่อนไหวโดยเปลี่ยนสีระหว่างสีเขียวและสีน้ำเงิน
รูปที่ 10 ตัวอย่างการแสดงสีข้อความเคลื่อนไหว

หากต้องการสร้างภาพเคลื่อนไหวสีข้อความ ให้ใช้แลมบ์ดา color ใน Composable BasicText ดังนี้

val infiniteTransition = rememberInfiniteTransition(label = "infinite transition")
val animatedColor by infiniteTransition.animateColor(
    initialValue = Color(0xFF60DDAD),
    targetValue = Color(0xFF4285F4),
    animationSpec = infiniteRepeatable(tween(1000), RepeatMode.Reverse),
    label = "color"
)

BasicText(
    text = "Hello Compose",
    color = {
        animatedColor
    },
    // ...
)

สลับระหว่างเนื้อหาประเภทต่างๆ

กรีนสกรีนที่ระบุว่ากำลังโหลด บลูสกรีนที่ระบุว่าโหลดแล้ว และไวท์สกรีนที่ระบุว่าเกิดข้อผิดพลาด โดยมีการวนซ้ำระหว่าง Composable ต่างๆ พร้อมภาพเคลื่อนไหวที่เรียบง่าย
รูปที่ 11 การใช้ AnimatedContent เพื่อทำให้การเปลี่ยนแปลงระหว่าง Composable ต่างๆ เคลื่อนไหว (ช้าลง)

ใช้ AnimatedContent เพื่อเปลี่ยนภาพระหว่าง Composable ต่างๆ หากต้องการเพียงแค่ให้ Composable ค่อยๆ จางหายไป ให้ใช้ Crossfade

var state by remember {
    mutableStateOf(UiState.Loading)
}
AnimatedContent(
    state,
    transitionSpec = {
        fadeIn(
            animationSpec = tween(3000)
        ) togetherWith fadeOut(animationSpec = tween(3000))
    },
    modifier = Modifier.clickable(
        interactionSource = remember { MutableInteractionSource() },
        indication = null
    ) {
        state = when (state) {
            UiState.Loading -> UiState.Loaded
            UiState.Loaded -> UiState.Error
            UiState.Error -> UiState.Loading
        }
    },
    label = "Animated Content"
) { targetState ->
    when (targetState) {
        UiState.Loading -> {
            LoadingScreen()
        }
        UiState.Loaded -> {
            LoadedScreen()
        }
        UiState.Error -> {
            ErrorScreen()
        }
    }
}

AnimatedContent สามารถปรับแต่งให้แสดงการเปลี่ยนฉากเข้าและออกได้หลายรูปแบบ อ่านข้อมูลเพิ่มเติมได้ในเอกสารประกอบเกี่ยวกับ AnimatedContent หรืออ่านบล็อกโพสต์นี้เกี่ยวกับ AnimatedContent

เคลื่อนไหวขณะนำทางไปยังจุดหมายต่างๆ

Composable 2 รายการ รายการหนึ่งเป็นสีเขียวที่ระบุว่า "หน้า Landing" และอีกรายการหนึ่งเป็นสีน้ำเงินที่ระบุว่า "รายละเอียด" โดยจะเคลื่อนไหวด้วยการเลื่อน Composable รายละเอียดไปไว้เหนือ Composable หน้า Landing
รูปที่ 12 สร้างภาพเคลื่อนไหวระหว่าง Composable โดยใช้ navigation-compose

หากต้องการเปลี่ยนภาพเคลื่อนไหวระหว่าง Composable เมื่อใช้ชิ้นงาน navigation-compose ให้ระบุ enterTransition และ exitTransition ใน Composable คุณยังตั้งค่าภาพเคลื่อนไหวเริ่มต้นที่จะใช้กับปลายทางทั้งหมดที่ระดับบนสุด NavHost ได้ด้วย

val navController = rememberNavController()
NavHost(
    navController = navController, startDestination = "landing",
    enterTransition = { EnterTransition.None },
    exitTransition = { ExitTransition.None }
) {
    composable("landing") {
        ScreenLanding(
            // ...
        )
    }
    composable(
        "detail/{photoUrl}",
        arguments = listOf(navArgument("photoUrl") { type = NavType.StringType }),
        enterTransition = {
            fadeIn(
                animationSpec = tween(
                    300, easing = LinearEasing
                )
            ) + slideIntoContainer(
                animationSpec = tween(300, easing = EaseIn),
                towards = AnimatedContentTransitionScope.SlideDirection.Start
            )
        },
        exitTransition = {
            fadeOut(
                animationSpec = tween(
                    300, easing = LinearEasing
                )
            ) + slideOutOfContainer(
                animationSpec = tween(300, easing = EaseOut),
                towards = AnimatedContentTransitionScope.SlideDirection.End
            )
        }
    ) { backStackEntry ->
        ScreenDetails(
            // ...
        )
    }
}

การเปลี่ยนฉากเข้าและออกมีหลายประเภท ซึ่งจะใช้เอฟเฟกต์ที่แตกต่างกันกับเนื้อหาที่เข้ามาและออกไป โปรดดูข้อมูลเพิ่มเติมในเอกสารประกอบ

เล่นภาพเคลื่อนไหวซ้ำ

พื้นหลังสีเขียวเปลี่ยนเป็นพื้นหลังสีน้ำเงินอย่างต่อเนื่องด้วยการเคลื่อนไหวระหว่าง 2 สี
รูปที่ 13 สีพื้นหลังเคลื่อนไหวระหว่าง 2 ค่าอย่างไม่มีที่สิ้นสุด

ใช้ rememberInfiniteTransition กับ infiniteRepeatable animationSpec เพื่อให้ภาพเคลื่อนไหวเล่นซ้ำไปเรื่อยๆ เปลี่ยน RepeatModes เพื่อ ระบุวิธีที่ควรจะไปกลับ

ใช้ repeatable เพื่อทำซ้ำตามจำนวนครั้งที่กำหนด

val infiniteTransition = rememberInfiniteTransition(label = "infinite")
val color by infiniteTransition.animateColor(
    initialValue = Color.Green,
    targetValue = Color.Blue,
    animationSpec = infiniteRepeatable(
        animation = tween(1000, easing = LinearEasing),
        repeatMode = RepeatMode.Reverse
    ),
    label = "color"
)
Column(
    modifier = Modifier.drawBehind {
        drawRect(color)
    }
) {
    // your composable here
}

เริ่มภาพเคลื่อนไหวเมื่อเปิดตัว Composable

LaunchedEffect จะทำงานเมื่อ Composable เข้าสู่ Composition โดยจะเริ่ม ภาพเคลื่อนไหวเมื่อเปิดตัว Composable คุณสามารถใช้เพื่อขับเคลื่อนการเปลี่ยนแปลงสถานะ ภาพเคลื่อนไหวได้ การใช้ Animatable กับเมธอด animateTo เพื่อเริ่มภาพเคลื่อนไหวเมื่อเปิดแอป

val alphaAnimation = remember {
    Animatable(0f)
}
LaunchedEffect(Unit) {
    alphaAnimation.animateTo(1f)
}
Box(
    modifier = Modifier.graphicsLayer {
        alpha = alphaAnimation.value
    }
)

สร้างภาพเคลื่อนไหวแบบต่อเนื่อง

วงกลม 4 วงที่มีลูกศรสีเขียวเคลื่อนไหวระหว่างแต่ละวง โดยจะเคลื่อนไหวทีละวง
รูปที่ 14 แผนภาพที่แสดงความคืบหน้าของภาพเคลื่อนไหวแบบลำดับทีละรายการ

ใช้ Animatable โครูทีน API เพื่อดำเนินการภาพเคลื่อนไหวแบบตามลำดับหรือพร้อมกัน การเรียกใช้ animateTo ใน Animatable ทีละรายการจะทำให้ ภาพเคลื่อนไหวแต่ละรายการรอให้ภาพเคลื่อนไหวรายการก่อนหน้าเสร็จสิ้นก่อนจึงจะดำเนินการต่อได้ เนื่องจากเป็นฟังก์ชันที่ระงับ

val alphaAnimation = remember { Animatable(0f) }
val yAnimation = remember { Animatable(0f) }

LaunchedEffect("animationKey") {
    alphaAnimation.animateTo(1f)
    yAnimation.animateTo(100f)
    yAnimation.animateTo(500f, animationSpec = tween(100))
}

สร้างภาพเคลื่อนไหวพร้อมกัน

วงกลม 3 วงที่มีลูกศรสีเขียวเคลื่อนไหวไปยังแต่ละวง และเคลื่อนไหวพร้อมกันทั้งหมดในเวลาเดียวกัน
รูปที่ 15 แผนภาพที่แสดงความคืบหน้าของภาพเคลื่อนไหวพร้อมกันทั้งหมด

ใช้ Coroutine API (Animatable#animateTo() หรือ animate) หรือ Transition API เพื่อสร้างภาพเคลื่อนไหวพร้อมกัน หากใช้ฟังก์ชันเปิดตัวหลายรายการในบริบทของ Coroutine ระบบจะเปิดตัวภาพเคลื่อนไหวพร้อมกัน

val alphaAnimation = remember { Animatable(0f) }
val yAnimation = remember { Animatable(0f) }

LaunchedEffect("animationKey") {
    launch {
        alphaAnimation.animateTo(1f)
    }
    launch {
        yAnimation.animateTo(100f)
    }
}

คุณสามารถใช้ updateTransition API เพื่อใช้สถานะเดียวกันในการขับเคลื่อน ภาพเคลื่อนไหวของพร็อพเพอร์ตี้ต่างๆ มากมายพร้อมกันได้ ตัวอย่างต่อไปนี้ จะเคลื่อนไหวพร็อพเพอร์ตี้ 2 รายการที่ควบคุมโดยการเปลี่ยนสถานะ rect และ borderWidth

var currentState by remember { mutableStateOf(BoxState.Collapsed) }
val transition = updateTransition(currentState, label = "transition")

val rect by transition.animateRect(label = "rect") { state ->
    when (state) {
        BoxState.Collapsed -> Rect(0f, 0f, 100f, 100f)
        BoxState.Expanded -> Rect(100f, 100f, 300f, 300f)
    }
}
val borderWidth by transition.animateDp(label = "borderWidth") { state ->
    when (state) {
        BoxState.Collapsed -> 1.dp
        BoxState.Expanded -> 0.dp
    }
}

เพิ่มประสิทธิภาพภาพเคลื่อนไหว

ภาพเคลื่อนไหวใน Compose อาจทำให้เกิดปัญหาด้านประสิทธิภาพได้ เนื่องจากลักษณะ ของภาพเคลื่อนไหวคือการย้ายหรือเปลี่ยนพิกเซลบนหน้าจออย่างรวดเร็ว ทีละเฟรมเพื่อสร้างภาพลวงตาของการเคลื่อนไหว

พิจารณาขั้นตอนต่างๆ ของฟีเจอร์แต่ง ได้แก่ การแต่ง การจัดวาง และการวาด หากภาพเคลื่อนไหวเปลี่ยนเฟสเลย์เอาต์ จะต้องมีการจัดเลย์เอาต์ใหม่และวาดใหม่สำหรับ Composable ทั้งหมดที่ได้รับผลกระทบ หากภาพเคลื่อนไหวเกิดขึ้นในเฟสการวาด ภาพเคลื่อนไหวจะทำงานได้ดีกว่าโดยค่าเริ่มต้นเมื่อเทียบกับการเรียกใช้ภาพเคลื่อนไหวในเฟสเลย์เอาต์ เนื่องจากโดยรวมแล้วจะมีงานที่ต้องทำน้อยกว่า

เลือกใช้ฟังก์ชันแลมบ์ดา ของ Modifier หากเป็นไปได้ เพื่อให้มั่นใจว่าแอปจะทำงานน้อยที่สุดขณะเคลื่อนไหว ซึ่งจะข้ามการจัดองค์ประกอบใหม่และทำการเคลื่อนไหว นอกระยะการจัดองค์ประกอบ หรือใช้ Modifier.graphicsLayer{ } เนื่องจากตัวแก้ไขนี้จะทำงานในระยะการวาดเสมอ ดูข้อมูลเพิ่มเติมได้ที่ส่วนการเลื่อนการอ่านใน เอกสารประกอบด้านประสิทธิภาพ

เปลี่ยนเวลาของภาพเคลื่อนไหว

โดยค่าเริ่มต้น Compose จะใช้ภาพเคลื่อนไหวแบบสปริงสำหรับภาพเคลื่อนไหวส่วนใหญ่ สปริงหรือภาพเคลื่อนไหวตามหลักฟิสิกส์จะดูเป็นธรรมชาติมากกว่า นอกจากนี้ยังหยุดชะงักได้เนื่องจากจะพิจารณาความเร็วปัจจุบันของออบเจ็กต์แทนที่จะใช้เวลาคงที่ หากต้องการลบล้างค่าเริ่มต้น API ภาพเคลื่อนไหวทั้งหมดที่สาธิตก่อนหน้านี้จะมีความสามารถในการตั้งค่า animationSpec เพื่อปรับแต่งวิธีเรียกใช้ภาพเคลื่อนไหว ไม่ว่าคุณต้องการให้ภาพเคลื่อนไหวทำงานในช่วงระยะเวลาหนึ่งหรือให้มีความยืดหยุ่นมากขึ้น

สรุปตัวเลือก animationSpec ต่างๆ มีดังนี้

  • spring: ภาพเคลื่อนไหวตามหลักฟิสิกส์ ซึ่งเป็นค่าเริ่มต้นสำหรับภาพเคลื่อนไหวทั้งหมด คุณ สามารถเปลี่ยนความแข็งหรือ dampingRatio เพื่อให้ภาพเคลื่อนไหวมี รูปลักษณ์และความรู้สึกที่แตกต่างกัน
  • tween (ย่อมาจาก between): ภาพเคลื่อนไหวตามระยะเวลา โดยจะเคลื่อนไหว ระหว่างค่า 2 ค่าด้วยฟังก์ชัน Easing
  • keyframes: ข้อมูลจำเพาะสำหรับการระบุค่าที่จุดสำคัญบางจุดในภาพเคลื่อนไหว
  • repeatable: ข้อกำหนดตามระยะเวลาที่ทำงานตามจำนวนครั้งที่กำหนด ซึ่งระบุโดย RepeatMode
  • infiniteRepeatable: ข้อกำหนดตามระยะเวลาที่ทำงานตลอดไป
  • snap: สแนปไปยังค่าสุดท้ายทันทีโดยไม่มีภาพเคลื่อนไหว
ภาพเคลื่อนไหว 2 รายการที่แสดงให้เห็นว่าไม่มีชุดข้อมูลจำเพาะเทียบกับชุดข้อมูลจำเพาะของสปริงที่กำหนดเอง
รูปที่ 16 ไม่ได้ตั้งค่าข้อมูลจำเพาะเทียบกับชุดข้อมูลจำเพาะของสปริงที่กำหนดเอง

อ่านเอกสารประกอบฉบับสมบูรณ์เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับ animationSpecs

แหล่งข้อมูลเพิ่มเติม

ดูตัวอย่างภาพเคลื่อนไหวสนุกๆ เพิ่มเติมใน Compose ได้ที่