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

หากต้องการปรับแต่งวิธีการทำงานของภาพเคลื่อนไหวการเปลี่ยนองค์ประกอบที่แชร์ คุณสามารถใช้พารามิเตอร์ 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 แรก measured the child layout with the lookahead (or target) constraints. จากนั้นระบบจะปรับขนาดเลย์เอาต์ที่เสถียรของรายการย่อยให้พอดีกับขอบเขตที่แชร์ ScaleToBounds เปรียบเสมือน "มาตราส่วนกราฟิก" ระหว่างรัฐต่างๆ

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

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

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

ScaleToBounds

RemeasureToBounds

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

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

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

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

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

คลิปและการซ้อนทับ

แนวคิดสําคัญในการสร้างองค์ประกอบที่แชร์ใน Compose คือการเรนเดอร์คอมโพสิเบิลจะยกระดับเป็นเลเยอร์วางซ้อนเมื่อเริ่มการเปลี่ยนเพื่อจับคู่กับคอมโพสิเบิลปลายทาง เพื่อให้คอมโพสิเบิลต่างๆ แชร์องค์ประกอบได้ ผลที่ได้คือ องค์ประกอบจะหนีขอบเขตขององค์ประกอบหลักและการเปลี่ยนรูปแบบเลเยอร์ (เช่น อัลฟาและมาตราส่วน)

องค์ประกอบจะแสดงผลบนองค์ประกอบ 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 ต้องวางไว้ด้านบนขององค์ประกอบที่แชร์จนกว่าหน้าจอจะมองไม่เห็น การเพิ่มตัวแก้ไขลงในคอมโพสิเบิลจะยกระดับคอมโพสิเบิลนั้น

ไม่มี Modifier.renderInSharedTransitionScopeOverlay()

ด้วย Modifier.renderInSharedTransitionScopeOverlay()

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

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

(สังเกตว่ารายการอื่นๆ ในรายการเลื่อนลงอย่างไรเมื่อรายการหนึ่งเติบโตขึ้น)