API ภาพเคลื่อนไหวหลายรายการมักจะยอมรับพารามิเตอร์สำหรับการปรับแต่งลักษณะการทำงาน
ปรับแต่งภาพเคลื่อนไหวด้วยพารามิเตอร์ AnimationSpec
API ภาพเคลื่อนไหวส่วนใหญ่ช่วยให้นักพัฒนาแอปปรับแต่งข้อกำหนดของภาพเคลื่อนไหวได้โดยใช้พารามิเตอร์ AnimationSpec ที่ไม่บังคับ
val alpha: Float by animateFloatAsState( targetValue = if (enabled) 1f else 0.5f, // Configure the animation duration and easing. animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing), label = "alpha" )
AnimationSpecมีหลายประเภทสำหรับสร้างภาพเคลื่อนไหวประเภทต่างๆ
สร้างภาพเคลื่อนไหวตามหลักฟิสิกส์ด้วย spring
spring สร้างภาพเคลื่อนไหวตามหลักฟิสิกส์ระหว่างค่าเริ่มต้นและค่าสิ้นสุด โดยใช้พารามิเตอร์ 2 รายการ ได้แก่ dampingRatio และ stiffness
dampingRatio กำหนดว่าสปริงควรเด้งแค่ไหน ค่าเริ่มต้นคือ Spring.DampingRatioNoBouncy
stiffness กำหนดความเร็วที่สปริงควรเคลื่อนที่ไปยังค่าสิ้นสุด ค่าเริ่มต้นคือ Spring.StiffnessMedium
val value by animateFloatAsState( targetValue = 1f, animationSpec = spring( dampingRatio = Spring.DampingRatioHighBouncy, stiffness = Spring.StiffnessMedium ), label = "spring spec" )
spring สามารถจัดการกับการขัดจังหวะได้ราบรื่นกว่าประเภท AnimationSpec ที่อิงตามระยะเวลา เนื่องจากรับประกันความต่อเนื่องของความเร็วเมื่อค่าเป้าหมายเปลี่ยนแปลงระหว่างภาพเคลื่อนไหว spring ใช้เป็น AnimationSpec เริ่มต้นโดย API ภาพเคลื่อนไหวจำนวนมาก เช่น animate*AsState และ updateTransition
ตัวอย่างเช่น หากเราใช้การกำหนดค่า spring กับภาพเคลื่อนไหวต่อไปนี้ที่ขับเคลื่อนโดยการสัมผัสของผู้ใช้ เมื่อขัดจังหวะภาพเคลื่อนไหวขณะที่กำลังดำเนินอยู่ คุณจะเห็นว่าการใช้ tween ไม่ตอบสนองอย่างราบรื่นเท่ากับการใช้ spring
tween เทียบกับ spring สำหรับภาพเคลื่อนไหว และการขัดจังหวะภาพเคลื่อนไหวสร้างภาพเคลื่อนไหวระหว่างค่าเริ่มต้นและค่าสิ้นสุดด้วยเส้นโค้งการค่อยๆ เปลี่ยนด้วย tween
tween จะเคลื่อนไหวระหว่างค่าเริ่มต้นและค่าสิ้นสุดตามdurationMillisที่ระบุโดยใช้เส้นโค้งการค่อยๆ เปลี่ยน tween เป็นคำย่อของคำว่า "ระหว่าง"
เนื่องจากจะอยู่ระหว่างค่า 2 ค่า
นอกจากนี้ คุณยังระบุ delayMillis เพื่อเลื่อนเวลาเริ่มต้นของภาพเคลื่อนไหวได้ด้วย
val value by animateFloatAsState( targetValue = 1f, animationSpec = tween( durationMillis = 300, delayMillis = 50, easing = LinearOutSlowInEasing ), label = "tween delay" )
ดูข้อมูลเพิ่มเติมได้ที่การค่อยๆ เปลี่ยน
สร้างภาพเคลื่อนไหวให้มีค่าที่เฉพาะเจาะจงในบางช่วงเวลาด้วย keyframes
keyframes จะเคลื่อนไหวตามค่าสแนปชอตที่ระบุไว้ที่การประทับเวลาต่างๆ ในระยะเวลาของภาพเคลื่อนไหว ค่าภาพเคลื่อนไหวจะได้รับการประมาณค่าในช่วงระหว่างค่าคีย์เฟรม 2 ค่า ณ เวลาใดก็ตาม สำหรับคีย์เฟรมแต่ละรายการเหล่านี้ คุณสามารถระบุการค่อยๆ เปลี่ยนเพื่อกำหนดเส้นโค้งการประมาณค่าในช่วงได้
คุณจะระบุค่าที่ 0 มิลลิวินาทีและที่ระยะเวลาหรือไม่ก็ได้ หากคุณไม่ระบุค่าเหล่านี้ ระบบจะใช้ค่าเริ่มต้นเป็นค่าเริ่มต้นและค่าสิ้นสุดของภาพเคลื่อนไหวตามลำดับ
val value by animateFloatAsState( targetValue = 1f, animationSpec = keyframes { durationMillis = 375 0.0f at 0 using LinearOutSlowInEasing // for 0-15 ms 0.2f at 15 using FastOutLinearInEasing // for 15-75 ms 0.4f at 75 // ms 0.4f at 225 // ms }, label = "keyframe" )
สร้างภาพเคลื่อนไหวระหว่างคีย์เฟรมได้อย่างราบรื่นด้วย keyframesWithSplines
หากต้องการสร้างภาพเคลื่อนไหวที่เคลื่อนที่ตามเส้นโค้งที่ราบรื่นขณะเปลี่ยนค่า คุณสามารถใช้ข้อกำหนดของภาพเคลื่อนไหว keyframesWithSplines แทน keyframes ได้
val offset by animateOffsetAsState( targetValue = Offset(300f, 300f), animationSpec = keyframesWithSpline { durationMillis = 6000 Offset(0f, 0f) at 0 Offset(150f, 200f) atFraction 0.5f Offset(0f, 100f) atFraction 0.7f } )
คีย์เฟรมที่อิงตามเส้นโค้งมีประโยชน์อย่างยิ่งสำหรับการเคลื่อนไหว 2 มิติของรายการบนหน้าจอ
วิดีโอต่อไปนี้แสดงความแตกต่างระหว่าง keyframes และ keyframesWithSpline โดยใช้พิกัด x, y ชุดเดียวกันที่วงกลมควรเคลื่อนที่ตาม
keyframes
|
keyframesWithSplines
|
|---|---|
อย่างที่คุณเห็น คีย์เฟรมที่ใช้เส้นโค้งจะช่วยให้การเปลี่ยนระหว่างจุดต่างๆ ราบรื่นขึ้น เนื่องจากใช้เส้นโค้งเบซิเยร์เพื่อทำให้ภาพเคลื่อนไหวระหว่างรายการต่างๆ ราบรื่น ข้อกำหนดนี้มีประโยชน์สำหรับภาพเคลื่อนไหวที่กำหนดล่วงหน้า อย่างไรก็ตาม หากคุณทำงานกับจุดที่ผู้ใช้กำหนด คุณควรใช้สปริงเพื่อให้ได้ความราบรื่นที่คล้ายกันระหว่างจุดต่างๆ เนื่องจากสปริงสามารถขัดจังหวะได้
เล่นภาพเคลื่อนไหวซ้ำด้วย repeatable
repeatable จะเรียกใช้ภาพเคลื่อนไหวตามระยะเวลา (เช่น tween หรือ keyframes) ซ้ำๆ จนกว่าจะถึงจำนวนการทำซ้ำที่ระบุ คุณสามารถส่งพารามิเตอร์ repeatMode เพื่อระบุว่าภาพเคลื่อนไหวควรเล่นซ้ำโดยเริ่มจากจุดเริ่มต้น (RepeatMode.Restart) หรือจากจุดสิ้นสุด (RepeatMode.Reverse)
val value by animateFloatAsState( targetValue = 1f, animationSpec = repeatable( iterations = 3, animation = tween(durationMillis = 300), repeatMode = RepeatMode.Reverse ), label = "repeatable spec" )
เล่นภาพเคลื่อนไหวซ้ำไปเรื่อยๆ ด้วย infiniteRepeatable
infiniteRepeatable คล้ายกับ repeatable แต่จะทำซ้ำไปเรื่อยๆ อย่างไม่สิ้นสุด
val value by animateFloatAsState( targetValue = 1f, animationSpec = infiniteRepeatable( animation = tween(durationMillis = 300), repeatMode = RepeatMode.Reverse ), label = "infinite repeatable" )
ในการทดสอบที่ใช้ ComposeTestRule ภาพเคลื่อนไหวที่ใช้ infiniteRepeatable จะไม่ทำงาน ระบบจะแสดงผลคอมโพเนนต์โดยใช้ค่าเริ่มต้นของค่าที่เคลื่อนไหวแต่ละค่า
สแนปไปยังค่าสิ้นสุดทันทีด้วย snap
snap เป็น AnimationSpec พิเศษที่เปลี่ยนค่าเป็นค่าสิ้นสุดทันที คุณสามารถระบุ delayMillis เพื่อหน่วงเวลาเริ่มต้นของภาพเคลื่อนไหวได้
val value by animateFloatAsState( targetValue = 1f, animationSpec = snap(delayMillis = 50), label = "snap spec" )
ตั้งค่าฟังก์ชันการค่อยๆ เปลี่ยนที่กำหนดเอง
การดำเนินการ AnimationSpec ตามระยะเวลา (เช่น tween หรือ keyframes) จะใช้ Easing เพื่อปรับเศษส่วนของภาพเคลื่อนไหว ซึ่งช่วยให้ค่าภาพเคลื่อนไหวเพิ่มขึ้นและลดลงได้ แทนที่จะเคลื่อนไหวในอัตราคงที่ เศษส่วนคือค่าระหว่าง 0 (เริ่มต้น) ถึง 1.0 (สิ้นสุด) ซึ่งระบุจุดปัจจุบันในภาพเคลื่อนไหว
จริงๆ แล้วการค่อยๆ เปลี่ยนเป็นฟังก์ชันที่ใช้ค่าเศษส่วนระหว่าง 0 ถึง 1.0 และแสดงผลเป็นเลขจำนวนจริง ค่าที่แสดงผลอาจอยู่นอกขอบเขตเพื่อแสดงถึงการเกินหรือขาด คุณสร้างการค่อยๆ เปลี่ยนที่กำหนดเองได้เหมือนโค้ดด้านล่าง
val CustomEasing = Easing { fraction -> fraction * fraction } @Composable fun EasingUsage() { val value by animateFloatAsState( targetValue = 1f, animationSpec = tween( durationMillis = 300, easing = CustomEasing ), label = "custom easing" ) // …… }
Compose มีฟังก์ชัน Easing ในตัวหลายฟังก์ชันที่ครอบคลุม Use Case ส่วนใหญ่
ดูข้อมูลเพิ่มเติมเกี่ยวกับความเร็วที่ควรใช้ตามสถานการณ์ได้ที่ความเร็ว - Material Design
FastOutSlowInEasingLinearOutSlowInEasingFastOutLinearEasingLinearEasingCubicBezierEasing- ดูเพิ่มเติม
สร้างภาพเคลื่อนไหวของประเภทข้อมูลที่กำหนดเองโดยการแปลงเป็นและจาก AnimationVector
API ภาพเคลื่อนไหวของ Compose ส่วนใหญ่รองรับ Float, Color, Dp และประเภทข้อมูลพื้นฐานอื่นๆ เป็นค่าภาพเคลื่อนไหวโดยค่าเริ่มต้น แต่บางครั้งคุณอาจต้องทำให้ประเภทข้อมูลอื่นๆ เคลื่อนไหว รวมถึงประเภทข้อมูลที่กำหนดเองด้วย ในระหว่างภาพเคลื่อนไหว ค่าภาพเคลื่อนไหวจะแสดงเป็น AnimationVector ค่าจะถูกแปลงเป็น AnimationVector และในทางกลับกันโดย TwoWayConverter ที่เกี่ยวข้อง เพื่อให้ระบบภาพเคลื่อนไหวหลักสามารถจัดการค่าเหล่านั้นได้อย่างสม่ำเสมอ เช่น Int จะแสดงเป็น AnimationVector1D ที่มีค่า Float ค่าเดียว
TwoWayConverter สำหรับ Int จะมีลักษณะดังนี้
val IntToVector: TwoWayConverter<Int, AnimationVector1D> = TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })
Color เป็นชุดค่า 4 ค่า ได้แก่ แดง เขียว น้ำเงิน และอัลฟา ดังนั้น Color จึงแปลงเป็น AnimationVector4D ที่มีค่าแบบลอย 4 ค่า ด้วยวิธีนี้ ข้อมูลทุกประเภทที่ใช้ในภาพเคลื่อนไหวจะถูกแปลงเป็น AnimationVector1D, AnimationVector2D, AnimationVector3D หรือ AnimationVector4D โดยขึ้นอยู่กับมิติข้อมูล ซึ่งช่วยให้คอมโพเนนต์ต่างๆ ของออบเจ็กต์เคลื่อนไหวได้อย่างอิสระ โดยแต่ละคอมโพเนนต์จะมีการติดตามความเร็วของตัวเอง คุณเข้าถึงตัวแปลงในตัวสำหรับประเภทข้อมูลพื้นฐานได้โดยใช้ตัวแปลง เช่น Color.VectorConverter หรือ Dp.VectorConverter
เมื่อต้องการเพิ่มการรองรับประเภทข้อมูลใหม่เป็นค่าที่เคลื่อนไหวได้ คุณสามารถสร้าง TwoWayConverter ของคุณเองและส่งให้กับ API ตัวอย่างเช่น คุณสามารถใช้ animateValueAsState เพื่อสร้างภาพเคลื่อนไหวให้กับประเภทข้อมูลที่กำหนดเองได้ดังนี้
data class MySize(val width: Dp, val height: Dp) @Composable fun MyAnimation(targetSize: MySize) { val animSize: MySize by animateValueAsState( targetSize, TwoWayConverter( convertToVector = { size: MySize -> // Extract a float value from each of the `Dp` fields. AnimationVector2D(size.width.value, size.height.value) }, convertFromVector = { vector: AnimationVector2D -> MySize(vector.v1.dp, vector.v2.dp) } ), label = "size" ) }
รายการต่อไปนี้ประกอบด้วย VectorConverter ในตัวบางส่วน
Color.VectorConverterDp.VectorConverterOffset.VectorConverterInt.VectorConverterFloat.VectorConverterIntSize.VectorConverter
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- ภาพเคลื่อนไหวตามมูลค่า
- การพัฒนาโค้ดแบบวนซ้ำ {:#iterative-code-dev }
- ภาพเคลื่อนไหวใน Compose