ปรับแต่งการเปลี่ยนองค์ประกอบที่แชร์

หากต้องการปรับแต่งวิธีที่ภาพเคลื่อนไหวของการเปลี่ยนองค์ประกอบที่ใช้ร่วมกันทำงาน คุณสามารถใช้พารามิเตอร์ 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

รูปที่ 1 ตัวอย่างที่แสดงboundsTransformพารามิเตอร์
ต่างๆ

โหมดปรับขนาด

เมื่อเคลื่อนไหวระหว่างขอบเขตที่แชร์ 2 รายการ คุณสามารถตั้งค่าพารามิเตอร์ resizeMode เป็น RemeasureToBounds หรือ ScaleToBounds ได้ พารามิเตอร์นี้จะกำหนดวิธี การเปลี่ยนองค์ประกอบที่แชร์ระหว่าง 2 สถานะ ScaleToBounds จะวัดเลย์เอาต์ย่อยด้วยข้อจำกัดในการมองล่วงหน้า (หรือเป้าหมาย) ก่อน จากนั้นระบบจะปรับขนาดเลย์เอาต์ที่เสถียรของ บุตรหลานให้พอดีกับขอบเขตที่แชร์ ScaleToBounds สามารถมองได้ว่าเป็น "มาตราส่วนกราฟิก" ระหว่างสถานะ

ในทางตรงกันข้าม RemeasureToBounds จะวัดและจัดเลย์เอาต์ใหม่สำหรับเลย์เอาต์ย่อยของ sharedBounds โดยมีข้อจำกัดคงที่แบบเคลื่อนไหวตามขนาดเป้าหมาย การวัดซ้ำจะทริกเกอร์โดยการเปลี่ยนแปลงขนาดขอบเขต ซึ่งอาจเกิดขึ้น ทุกเฟรม

สำหรับ Composable ของ Text เราขอแนะนำให้ใช้ ScaleToBounds เนื่องจากจะช่วยหลีกเลี่ยงการจัดวางใหม่ และการเปลี่ยนบรรทัดข้อความ RemeasureToBounds ขอแนะนำ สำหรับขอบเขตที่มีสัดส่วนภาพต่างกัน และหากคุณต้องการให้องค์ประกอบที่แชร์ 2 รายการมีความต่อเนื่องที่ราบรื่น

ความแตกต่างระหว่างโหมดปรับขนาดทั้ง 2 โหมดจะเห็นได้ในตัวอย่างต่อไปนี้

ScaleToBounds

RemeasureToBounds

ข้ามไปยังเลย์เอาต์สุดท้าย

โดยค่าเริ่มต้น เมื่อเปลี่ยนระหว่างเลย์เอาต์ 2 แบบ ขนาดเลย์เอาต์จะเคลื่อนไหว ระหว่างสถานะเริ่มต้นและสถานะสุดท้าย ซึ่งอาจเป็นลักษณะการทำงานที่ไม่พึงประสงค์เมื่อ สร้างภาพเคลื่อนไหวเนื้อหา เช่น ข้อความ

ตัวอย่างต่อไปนี้แสดงข้อความคำอธิบาย "Lorem Ipsum" ที่ปรากฏบนหน้าจอใน 2 วิธีที่แตกต่างกัน ในตัวอย่างแรก ข้อความจะปรับให้พอดีกับคอนเทนเนอร์เมื่อคอนเทนเนอร์มีขนาดใหญ่ขึ้น ในตัวอย่างที่ 2 ข้อความจะไม่ จัดข้อความใหม่เมื่อขยาย การเพิ่ม Modifier.skipToLookaheadSize() จะป้องกันการปรับข้อความใหม่ เมื่อข้อความยาวขึ้น

ไม่มี Modifier.skipToLookahead() - สังเกตข้อความ "Lorem Ipsum" ที่มีการปรับข้อความใหม่

Modifier.skipToLookahead() - สังเกตว่าข้อความ "Lorem Ipsum" ยังคงมีสถานะสุดท้ายที่จุดเริ่มต้นของภาพเคลื่อนไหว

คลิปและภาพซ้อนทับ

เพื่อให้องค์ประกอบที่แชร์ใช้ร่วมกันระหว่าง 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 นั้นยังคงอยู่

ไม่มีModifier.renderInSharedTransitionScopeOverlay()

ด้วย Modifier.renderInSharedTransitionScopeOverlay()

คุณอาจต้องการให้ Composable ที่ไม่ได้แชร์เคลื่อนไหวออกไปและ ยังคงอยู่เหนือ Composable อื่นๆ ก่อนการเปลี่ยน ในกรณีเช่นนี้ ให้ใช้ renderInSharedTransitionScopeOverlay().animateEnterExit() เพื่อเคลื่อนไหว Composables ออกขณะที่การเปลี่ยนภาพองค์ประกอบที่แชร์ทำงานอยู่

JetsnackBottomBar(
    modifier = Modifier
        .renderInSharedTransitionScopeOverlay(
            zIndexInOverlay = 1f,
        )
        .animateEnterExit(
            enter = fadeIn() + slideInVertically {
                it
            },
            exit = fadeOut() + slideOutVertically {
                it
            }
        )
)

รูปที่ 2 แถบแอปด้านล่างเลื่อนเข้าและออกเมื่อภาพเคลื่อนไหวเปลี่ยน

ในกรณีที่ไม่ได้เกิดขึ้นบ่อยนัก หากคุณไม่ต้องการให้องค์ประกอบที่แชร์แสดงใน ภาพซ้อนทับ คุณสามารถตั้งค่า renderInOverlayDuringTransition ใน sharedElement() เป็น false ได้

แจ้งเลย์เอาต์ที่เกี่ยวข้องเกี่ยวกับการเปลี่ยนแปลงขนาดขององค์ประกอบที่แชร์

โดยค่าเริ่มต้น sharedBounds() และ sharedElement() จะไม่แจ้งให้คอนเทนเนอร์ระดับบนสุดทราบถึงการเปลี่ยนแปลงขนาดใดๆ เมื่อเลย์เอาต์เปลี่ยน

หากต้องการเผยแพร่การเปลี่ยนแปลงขนาดไปยังคอนเทนเนอร์ระดับบนสุดเมื่อมีการเปลี่ยน ให้เปลี่ยนพารามิเตอร์ placeHolderSize เป็น PlaceHolderSize.animatedSize การทำเช่นนี้จะทำให้ไอเทมขยายหรือหดตัว รายการอื่นๆ ทั้งหมดในเลย์เอาต์จะตอบสนองต่อ การเปลี่ยนแปลง

PlaceholderSize.contentSize (ค่าเริ่มต้น)

PlaceholderSize.animatedSize

(สังเกตว่ารายการอื่นๆ ในลิสต์จะเลื่อนลงเมื่อมีรายการหนึ่งเพิ่มขึ้น)