หากต้องการปรับแต่งวิธีที่ภาพเคลื่อนไหวของการเปลี่ยนองค์ประกอบที่ใช้ร่วมกันทำงาน คุณสามารถใช้พารามิเตอร์ 2-3 รายการเพื่อเปลี่ยนวิธีที่องค์ประกอบที่ใช้ร่วมกันเปลี่ยนภาพ
ข้อกำหนดของภาพเคลื่อนไหว
หากต้องการเปลี่ยนข้อกำหนดของภาพเคลื่อนไหวที่ใช้สำหรับการเคลื่อนไหวของขนาดและตำแหน่ง คุณสามารถ
ระบุboundsTransformพารามิเตอร์อื่นใน Modifier.sharedElement() ได้
ซึ่งจะระบุRectตำแหน่งเริ่มต้นและRectตำแหน่งเป้าหมาย
เช่น หากต้องการให้ข้อความในตัวอย่างก่อนหน้าเคลื่อนที่ตามส่วนโค้ง
ให้ระบุพารามิเตอร์ boundsTransform เพื่อใช้ข้อกำหนด keyframes
val textBoundsTransform = BoundsTransform { initialBounds, targetBounds -> keyframes { durationMillis = boundsAnimationDurationMillis initialBounds at 0 using ArcMode.ArcBelow using FastOutSlowInEasing targetBounds at boundsAnimationDurationMillis } } Text( "Cupcake", fontSize = 28.sp, modifier = Modifier.sharedBounds( rememberSharedContentState(key = "title"), animatedVisibilityScope = animatedVisibilityScope, boundsTransform = textBoundsTransform ) )
คุณใช้ AnimationSpec ใดก็ได้ ตัวอย่างนี้ใช้ข้อกำหนด keyframes
boundsTransformพารามิเตอร์โหมดปรับขนาด
เมื่อเคลื่อนไหวระหว่างขอบเขตที่แชร์ 2 รายการ คุณสามารถตั้งค่าพารามิเตอร์ resizeMode
เป็น RemeasureToBounds หรือ ScaleToBounds ได้ พารามิเตอร์นี้จะกำหนดวิธี
การเปลี่ยนองค์ประกอบที่แชร์ระหว่าง 2 สถานะ ScaleToBounds first
วัดเลย์เอาต์ย่อยด้วยข้อจำกัดแบบมองไปข้างหน้า (หรือเป้าหมาย) จากนั้นระบบจะปรับขนาดเลย์เอาต์ที่เสถียรของ
บุตรหลานให้พอดีกับขอบเขตที่แชร์
ScaleToBounds สามารถมองได้ว่าเป็น "มาตราส่วนกราฟิก" ระหว่างสถานะ
ในทางตรงกันข้าม RemeasureToBounds จะวัดและจัดเลย์เอาต์ใหม่สำหรับเลย์เอาต์ย่อยของ
sharedBounds โดยมีข้อจำกัดคงที่แบบเคลื่อนไหวตามขนาดเป้าหมาย
การวัดซ้ำจะทริกเกอร์โดยการเปลี่ยนแปลงขนาดขอบเขต ซึ่งอาจเกิดขึ้น
ทุกเฟรม
สำหรับ Composable ของ Text เราขอแนะนำให้ใช้ ScaleToBounds เนื่องจากจะช่วยหลีกเลี่ยงการจัดวางใหม่
และการจัดข้อความใหม่ในบรรทัดต่างๆ RemeasureToBounds ขอแนะนำ
สำหรับขอบเขตที่มีสัดส่วนภาพต่างกัน และหากคุณต้องการให้องค์ประกอบที่แชร์ทั้ง 2 รายการมีความต่อเนื่องอย่างราบรื่น
ความแตกต่างระหว่างโหมดปรับขนาดทั้ง 2 โหมดจะแสดงในตัวอย่างต่อไปนี้
|
|
|---|---|
เปิดและปิดใช้องค์ประกอบที่แชร์แบบไดนามิก
โดยค่าเริ่มต้น ระบบจะกำหนดค่า sharedElement() และ sharedBounds() ให้เคลื่อนไหวการเปลี่ยนแปลงเลย์เอาต์ทุกครั้งที่พบคีย์ที่ตรงกันในสถานะเป้าหมาย อย่างไรก็ตาม
คุณอาจต้องการปิดใช้ภาพเคลื่อนไหวนี้แบบไดนามิกตามเงื่อนไขที่เฉพาะเจาะจง
เช่น ทิศทางการนำทางหรือสถานะ UI ปัจจุบัน
หากต้องการควบคุมว่าจะให้มีการเปลี่ยนฉากขององค์ประกอบที่แชร์หรือไม่ คุณสามารถปรับแต่ง
SharedContentConfigที่ส่งไปยัง rememberSharedContentState() ได้ พร็อพเพอร์ตี้ isEnabled
จะกำหนดว่าองค์ประกอบที่แชร์ใช้งานอยู่หรือไม่
ตัวอย่างต่อไปนี้แสดงวิธีกำหนดค่าที่ เปิดใช้ภาพเคลื่อนไหวที่แชร์เมื่อไปยังส่วนต่างๆ ระหว่างหน้าจอที่เฉพาะเจาะจง (เช่น จาก A ไปยัง B เท่านั้น) ขณะเดียวกันก็ปิดใช้สำหรับหน้าจออื่นๆ
SharedTransitionLayout { val transition = updateTransition(currentState) transition.AnimatedContent { targetState -> // Create the configuration that depends on state changing. fun animationConfig() : SharedTransitionScope.SharedContentConfig { return object : SharedTransitionScope.SharedContentConfig { override val SharedTransitionScope.SharedContentState.isEnabled: Boolean // For this example, we only enable the transition in one direction // from A -> B and not the other way around. get() = transition.currentState == "A" && transition.targetState == "B" } } when (targetState) { "A" -> Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } "B" -> { Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } } } } }
โดยค่าเริ่มต้น หากปิดใช้องค์ประกอบที่แชร์ระหว่างภาพเคลื่อนไหวที่กำลังดำเนินการอยู่ องค์ประกอบนั้นจะยังคงทำให้ภาพเคลื่อนไหวที่กำลังดำเนินการอยู่เสร็จสมบูรณ์เพื่อป้องกันไม่ให้มีการนำภาพเคลื่อนไหวที่กำลังดำเนินการอยู่ออกโดยไม่ตั้งใจ หากต้องการนำองค์ประกอบออกขณะที่
ภาพเคลื่อนไหวกำลังดำเนินการอยู่ คุณสามารถลบล้าง
shouldKeepEnabledForOngoingAnimation ในอินเทอร์เฟซ SharedContentConfig เพื่อ
ส่งคืนค่าเป็นเท็จ
ข้ามไปยังเลย์เอาต์สุดท้าย
โดยค่าเริ่มต้น เมื่อเปลี่ยนจากเลย์เอาต์หนึ่งไปยังอีกเลย์เอาต์หนึ่ง ขนาดเลย์เอาต์จะเคลื่อนไหว ระหว่างสถานะเริ่มต้นและสถานะสุดท้าย ซึ่งอาจเป็นลักษณะการทำงานที่ไม่พึงประสงค์เมื่อ เคลื่อนไหวเนื้อหา เช่น ข้อความ
ตัวอย่างต่อไปนี้แสดงข้อความคำอธิบาย "Lorem Ipsum" ที่ปรากฏบนหน้าจอ
ใน 2 วิธีที่แตกต่างกัน ในตัวอย่างแรก ข้อความจะไหลใหม่เมื่อ
ป้อนข้อความขณะที่คอนเทนเนอร์มีขนาดใหญ่ขึ้น ในตัวอย่างที่ 2 ข้อความจะไม่
จัดข้อความใหม่เมื่อขยาย การเพิ่ม Modifier.skipToLookaheadSize() จะป้องกันการปรับข้อความใหม่
เมื่อข้อความยาวขึ้น
ไม่มี |
|
|---|---|
คลิปและภาพซ้อนทับ
เพื่อให้องค์ประกอบที่แชร์ใช้ร่วมกันระหว่าง Composable ต่างๆ ได้ การแสดงผลของ Composable จะได้รับการยกระดับเป็นเลเยอร์ซ้อนทับเมื่อ เริ่มการเปลี่ยนไปยังองค์ประกอบที่ตรงกันในปลายทาง ซึ่งจะทำให้ หลุดออกจากขอบเขตขององค์ประกอบหลักและการแปลงเลเยอร์ (เช่น อัลฟ่าและสเกล)
โดยจะแสดงทับองค์ประกอบ UI อื่นๆ ที่ไม่ได้แชร์ เมื่อการเปลี่ยนผ่าน
เสร็จสมบูรณ์แล้ว ระบบจะวางองค์ประกอบจากภาพซ้อนทับลงในDrawScopeขององค์ประกอบนั้นเอง
หากต้องการตัดองค์ประกอบที่ใช้ร่วมกันให้เป็นรูปทรง ให้ใช้ฟังก์ชัน Modifier.clip()
มาตรฐาน วางไว้หลัง sharedElement() ดังนี้
Image( painter = painterResource(id = R.drawable.cupcake), contentDescription = "Cupcake", modifier = Modifier .size(100.dp) .sharedElement( rememberSharedContentState(key = "image"), animatedVisibilityScope = this@AnimatedContent ) .clip(RoundedCornerShape(16.dp)), contentScale = ContentScale.Crop )
หากต้องการให้มั่นใจว่าองค์ประกอบที่แชร์จะไม่แสดงนอกคอนเทนเนอร์หลัก คุณสามารถตั้งค่า clipInOverlayDuringTransition ใน sharedElement() ได้ โดยค่าเริ่มต้นสำหรับขอบเขตที่แชร์แบบซ้อน clipInOverlayDuringTransition จะใช้เส้นทางคลิปจาก sharedBounds() ระดับบน
หากต้องการรองรับการคงองค์ประกอบ UI บางอย่าง เช่น แถบด้านล่างหรือปุ่มการทำงานแบบลอย
ไว้ที่ด้านบนเสมอในระหว่างการเปลี่ยนองค์ประกอบที่แชร์ ให้ใช้
Modifier.renderInSharedTransitionScopeOverlay() โดยค่าเริ่มต้น ตัวแก้ไขนี้จะเก็บเนื้อหาไว้ในภาพซ้อนทับในระหว่างที่ทรานซิชันที่แชร์ทำงานอยู่
ตัวอย่างเช่น ใน Jetsnack คุณต้องวาง BottomAppBar ไว้เหนือองค์ประกอบที่แชร์จนกว่าหน้าจอจะไม่แสดง การเพิ่มตัวแก้ไข
ลงใน Composable จะช่วยให้ Composable นั้นยังคงอยู่ในระดับสูง
ไม่มี |
ด้วย |
|---|---|
คุณอาจต้องการให้ Composable ที่ไม่ได้แชร์เคลื่อนไหวออกไปและ
ยังคงอยู่เหนือ Composable อื่นๆ ก่อนการเปลี่ยน ในกรณีเช่นนี้ ให้ใช้
renderInSharedTransitionScopeOverlay().animateEnterExit() เพื่อเคลื่อนไหว
Composable ออกเมื่อการเปลี่ยนภาพองค์ประกอบที่แชร์ทำงาน
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
ในกรณีที่ไม่ได้เกิดขึ้นบ่อยนัก หากคุณไม่ต้องการให้องค์ประกอบที่แชร์แสดงใน
ภาพซ้อนทับ คุณสามารถตั้งค่า renderInOverlayDuringTransition ใน sharedElement()
เป็น false ได้
แจ้งเลย์เอาต์ที่เกี่ยวข้องเกี่ยวกับการเปลี่ยนแปลงขนาดขององค์ประกอบที่แชร์
โดยค่าเริ่มต้น sharedBounds() และ sharedElement() จะไม่แจ้งให้คอนเทนเนอร์ระดับบนสุดทราบถึงการเปลี่ยนแปลงขนาดใดๆ เมื่อเลย์เอาต์เปลี่ยน
หากต้องการเผยแพร่การเปลี่ยนแปลงขนาดไปยังคอนเทนเนอร์ระดับบนสุดเมื่อมีการเปลี่ยน
ให้เปลี่ยนพารามิเตอร์ placeholderSize เป็น PlaceholderSize.AnimatedSize การทำเช่นนี้จะทำให้ไอเทมขยายหรือหดตัว รายการอื่นๆ ทั้งหมดในเลย์เอาต์จะตอบสนองต่อ
การเปลี่ยนแปลง
|
(สังเกตว่ารายการอื่นๆ ในรายการจะเลื่อนลงเมื่อมีรายการหนึ่งเพิ่มขึ้น) |
|---|---|