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

หากต้องการปรับแต่งวิธีเรียกใช้ภาพเคลื่อนไหวการเปลี่ยนองค์ประกอบที่แชร์ ให้ทำดังนี้ ที่ใช้เปลี่ยนวิธีเปลี่ยนองค์ประกอบที่แชร์

ข้อมูลจำเพาะของภาพเคลื่อนไหว

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

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

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

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

ScaleToBounds

RemeasureToBounds

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

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

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

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

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

คลิปและการวางซ้อน

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

ไม่มีModifier.renderInSharedTransitionScopeOverlay()

ด้วย Modifier.renderInSharedTransitionScopeOverlay()

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

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

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

คุณอาจไม่ต้องการให้องค์ประกอบที่แชร์แสดงผลใน คุณสามารถตั้งค่า renderInOverlayDuringTransition ใน sharedElement() ได้ เป็นเท็จ

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

โดยค่าเริ่มต้น sharedBounds() และ sharedElement() จะไม่แจ้งให้ผู้ปกครองทราบ ขนาดใดก็ได้จะเปลี่ยนไปตามการเปลี่ยนเลย์เอาต์

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

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

PlaceholderSize.animatedSize

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