เราได้เปิดตัว API ใหม่เพื่อปรับปรุงประสิทธิภาพการเขียนของคอมโพเนนต์แบบอินเทอร์แอกทีฟที่ใช้
Modifier.clickable API เหล่านี้ช่วยให้Indicationการใช้งานมีประสิทธิภาพมากขึ้น เช่น การกระเพื่อม
androidx.compose.foundation:foundation:1.7.0+ และ
androidx.compose.material:material-ripple:1.7.0+ มีการเปลี่ยนแปลง API
ดังต่อไปนี้
เลิกใช้งาน |
การเปลี่ยนทดแทน |
|---|---|
|
|
|
หมายเหตุ: ในบริบทนี้ "คลังวัสดุ" หมายถึง |
|
ดังนี้
|
หน้านี้อธิบายผลกระทบจากการเปลี่ยนแปลงลักษณะการทำงานและวิธีการย้ายข้อมูลไปยัง API ใหม่
การเปลี่ยนแปลงพฤติกรรม
ไลบรารีเวอร์ชันต่อไปนี้มีการเปลี่ยนแปลงลักษณะการทำงานของ Ripple
androidx.compose.material:material:1.7.0+androidx.compose.material3:material3:1.3.0+androidx.wear.compose:compose-material:1.4.0+
ไลบรารี Material เวอร์ชันเหล่านี้จะไม่ใช้ rememberRipple() อีกต่อไป แต่จะใช้
API การกระเพื่อมใหม่แทน ด้วยเหตุนี้ จึงไม่ได้ส่งคำค้นหา LocalRippleTheme
ดังนั้น หากคุณตั้งค่า LocalRippleTheme ในแอปพลิเคชัน Material
components จะไม่ใช้ค่าเหล่านี้
ส่วนต่อไปนี้จะอธิบายวิธีย้ายข้อมูลไปยัง API ใหม่
ย้ายข้อมูลจาก rememberRipple ไปยัง ripple
การใช้คลังวัสดุ
หากคุณใช้ไลบรารี Material ให้แทนที่ rememberRipple() ด้วยการเรียก ripple() จากไลบรารีที่เกี่ยวข้องโดยตรง API นี้จะสร้าง Ripple
โดยใช้ค่าที่ได้จาก Material Theme API จากนั้นส่งออบเจ็กต์ที่ส่งคืน
ไปยัง Modifier.clickable และ/หรือคอมโพเนนต์อื่นๆ
เช่น ข้อมูลโค้ดต่อไปนี้ใช้ API ที่เลิกใช้งานแล้ว
Box( Modifier.clickable( onClick = {}, interactionSource = remember { MutableInteractionSource() }, indication = rememberRipple() ) ) { // ... }
คุณควรแก้ไขข้อมูลโค้ดข้างต้นเพื่อทำสิ่งต่อไปนี้
@Composable private fun RippleExample() { Box( Modifier.clickable( onClick = {}, interactionSource = remember { MutableInteractionSource() }, indication = ripple() ) ) { // ... } }
โปรดทราบว่า ripple() ไม่ใช่ฟังก์ชันที่ประกอบกันได้อีกต่อไปและไม่จำเป็นต้องจดจำ นอกจากนี้ยังนำไปใช้ซ้ำในคอมโพเนนต์หลายรายการได้ด้วย เช่นเดียวกับ
ตัวแก้ไข ดังนั้นให้พิจารณาดึงการสร้าง Ripple ไปยังค่าระดับบนสุดเพื่อ
ประหยัดการจัดสรร
การใช้ระบบการออกแบบที่กำหนดเอง
หากคุณกำลังใช้ระบบการออกแบบของคุณเอง และก่อนหน้านี้ใช้ rememberRipple() ร่วมกับ RippleTheme ที่กำหนดเองเพื่อกำหนดค่า Ripple คุณควรระบุ Ripple API ของคุณเองแทน ซึ่งจะมอบสิทธิ์ให้กับ API ของโหนด Ripple ที่แสดงใน material-ripple จากนั้น คอมโพเนนต์จะใช้ Ripple ของคุณเอง
ซึ่งใช้ค่าธีมโดยตรงได้ ดูข้อมูลเพิ่มเติมได้ที่ย้ายข้อมูล
จากRippleTheme
ย้ายข้อมูลจาก RippleTheme
การใช้ RippleTheme เพื่อปิดใช้ Ripple สำหรับคอมโพเนนต์ที่ต้องการ
ไลบรารี material และ material3 แสดง RippleConfiguration และ
LocalRippleConfiguration ซึ่งช่วยให้คุณกำหนดค่าลักษณะที่ปรากฏของ
เอฟเฟกต์ระลอกภายในซับทรีได้ โปรดทราบว่า RippleConfiguration และ
LocalRippleConfiguration มีไว้สําหรับการปรับแต่ง
ต่อคอมโพเนนต์เท่านั้น API เหล่านี้ไม่รองรับการปรับแต่งทั่วโลก/ทั้งธีม ดูข้อมูลเพิ่มเติมเกี่ยวกับกรณีการใช้งานดังกล่าวได้ที่การใช้ RippleTheme เพื่อเปลี่ยนการกระเพื่อมทั้งหมดในแอปพลิเคชันทั่วโลก
เช่น ข้อมูลโค้ดต่อไปนี้ใช้ API ที่เลิกใช้งานแล้ว
private object DisabledRippleTheme : RippleTheme { @Composable override fun defaultColor(): Color = Color.Transparent @Composable override fun rippleAlpha(): RippleAlpha = RippleAlpha(0f, 0f, 0f, 0f) } // ... CompositionLocalProvider(LocalRippleTheme provides DisabledRippleTheme) { Button { // ... } }
คุณควรแก้ไขข้อมูลโค้ดข้างต้นเพื่อทำสิ่งต่อไปนี้
CompositionLocalProvider(LocalRippleConfiguration provides null) { Button { // ... } }
การใช้ RippleTheme เพื่อเปลี่ยนสี/อัลฟ่าของ Ripple สำหรับคอมโพเนนต์ที่กำหนด
ดังที่อธิบายไว้ในส่วนก่อนหน้า RippleConfiguration และ
LocalRippleConfiguration มีไว้สำหรับการปรับแต่งต่อคอมโพเนนต์เท่านั้น
เช่น ข้อมูลโค้ดต่อไปนี้ใช้ API ที่เลิกใช้งานแล้ว
private object DisabledRippleThemeColorAndAlpha : RippleTheme { @Composable override fun defaultColor(): Color = Color.Red @Composable override fun rippleAlpha(): RippleAlpha = MyRippleAlpha } // ... CompositionLocalProvider(LocalRippleTheme provides DisabledRippleThemeColorAndAlpha) { Button { // ... } }
คุณควรแก้ไขข้อมูลโค้ดข้างต้นเพื่อทำสิ่งต่อไปนี้
@OptIn(ExperimentalMaterialApi::class) private val MyRippleConfiguration = RippleConfiguration(color = Color.Red, rippleAlpha = MyRippleAlpha) // ... CompositionLocalProvider(LocalRippleConfiguration provides MyRippleConfiguration) { Button { // ... } }
การใช้ RippleTheme เพื่อเปลี่ยนการกระเพื่อมทั้งหมดในแอปพลิเคชันทั่วโลก
ก่อนหน้านี้ คุณสามารถใช้ LocalRippleTheme เพื่อกำหนดลักษณะการกระเพื่อมที่ระดับธีมทั้งหมดได้ ซึ่งเป็นจุดผสานรวมระหว่างองค์ประกอบระบบการออกแบบที่กำหนดเองกับ Ripple material-ripple ตอนนี้จะแสดงฟังก์ชัน createRippleModifierNode() แทนที่จะแสดงองค์ประกอบการจัดรูปแบบทั่วไป
ฟังก์ชันนี้ช่วยให้ไลบรารีระบบการออกแบบสร้างการใช้งานwrapperระดับสูงขึ้นได้ ซึ่งจะค้นหาค่าธีม แล้วมอบหมายการใช้งาน Ripple ให้กับโหนดที่สร้างขึ้นโดยฟังก์ชันนี้
ซึ่งช่วยให้ระบบการออกแบบสามารถค้นหาสิ่งที่ต้องการได้โดยตรง และแสดงเลเยอร์การจัดธีมที่ผู้ใช้กำหนดค่าได้ตามต้องการที่ด้านบนโดยไม่ต้องยึดตามสิ่งที่ระบุไว้ในเลเยอร์ material-ripple การเปลี่ยนแปลงนี้ยังทำให้ธีม/ข้อกำหนดที่ริปเปิลเป็นไปตามนั้นชัดเจนยิ่งขึ้นด้วย เนื่องจากเป็น API ของริปเปิลเองที่กำหนดสัญญาดังกล่าว ไม่ใช่การอนุมานจากธีมโดยปริยาย
ดูคำแนะนำได้ที่การใช้งาน Ripple API ในไลบรารี Material และแทนที่การเรียกไปยัง Material Composition Local ตามที่จำเป็นสำหรับ ระบบการออกแบบของคุณเอง
ย้ายข้อมูลจาก Indication ไปยัง IndicationNodeFactory
ผ่านประมาณ Indication
หากคุณเพียงสร้าง Indication เพื่อส่งต่อ เช่น สร้าง
การกระเพื่อมเพื่อส่งต่อให้ Modifier.clickable หรือ Modifier.indication คุณก็ไม่
จำเป็นต้องทำการเปลี่ยนแปลงใดๆ IndicationNodeFactory สืบทอดมาจาก Indication
ดังนั้นทุกอย่างจะยังคงคอมไพล์และทำงานได้
กำลังสร้าง Indication
หากคุณสร้างIndicationการติดตั้งใช้งานของคุณเอง การย้ายข้อมูลควร
จะง่ายในกรณีส่วนใหญ่ ตัวอย่างเช่น ลองพิจารณา Indication ที่ใช้เอฟเฟกต์การปรับขนาดเมื่อกด
object ScaleIndication : Indication { @Composable override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance { // key the remember against interactionSource, so if it changes we create a new instance val instance = remember(interactionSource) { ScaleIndicationInstance() } LaunchedEffect(interactionSource) { interactionSource.interactions.collectLatest { interaction -> when (interaction) { is PressInteraction.Press -> instance.animateToPressed(interaction.pressPosition) is PressInteraction.Release -> instance.animateToResting() is PressInteraction.Cancel -> instance.animateToResting() } } } return instance } } private class ScaleIndicationInstance : IndicationInstance { var currentPressPosition: Offset = Offset.Zero val animatedScalePercent = Animatable(1f) suspend fun animateToPressed(pressPosition: Offset) { currentPressPosition = pressPosition animatedScalePercent.animateTo(0.9f, spring()) } suspend fun animateToResting() { animatedScalePercent.animateTo(1f, spring()) } override fun ContentDrawScope.drawIndication() { scale( scale = animatedScalePercent.value, pivot = currentPressPosition ) { this@drawIndication.drawContent() } } }
คุณย้ายข้อมูลนี้ได้ใน 2 ขั้นตอน ดังนี้
ย้ายข้อมูล
ScaleIndicationInstanceเพื่อเป็นDrawModifierNodeAPI Surface สำหรับDrawModifierNodeคล้ายกับIndicationInstanceมาก โดยจะแสดงฟังก์ชันContentDrawScope#draw()ซึ่งเทียบเท่ากับIndicationInstance#drawContent()ในด้านฟังก์ชันการทำงาน คุณต้องเปลี่ยนฟังก์ชันนั้น แล้ว ใช้ตรรกะcollectLatestภายในโหนดโดยตรงแทนIndicationเช่น ข้อมูลโค้ดต่อไปนี้ใช้ API ที่เลิกใช้งานแล้ว
private class ScaleIndicationInstance : IndicationInstance { var currentPressPosition: Offset = Offset.Zero val animatedScalePercent = Animatable(1f) suspend fun animateToPressed(pressPosition: Offset) { currentPressPosition = pressPosition animatedScalePercent.animateTo(0.9f, spring()) } suspend fun animateToResting() { animatedScalePercent.animateTo(1f, spring()) } override fun ContentDrawScope.drawIndication() { scale( scale = animatedScalePercent.value, pivot = currentPressPosition ) { this@drawIndication.drawContent() } } }
คุณควรแก้ไขข้อมูลโค้ดข้างต้นเพื่อดำเนินการต่อไปนี้
private class ScaleIndicationNode( private val interactionSource: InteractionSource ) : Modifier.Node(), DrawModifierNode { var currentPressPosition: Offset = Offset.Zero val animatedScalePercent = Animatable(1f) private suspend fun animateToPressed(pressPosition: Offset) { currentPressPosition = pressPosition animatedScalePercent.animateTo(0.9f, spring()) } private suspend fun animateToResting() { animatedScalePercent.animateTo(1f, spring()) } override fun onAttach() { coroutineScope.launch { interactionSource.interactions.collectLatest { interaction -> when (interaction) { is PressInteraction.Press -> animateToPressed(interaction.pressPosition) is PressInteraction.Release -> animateToResting() is PressInteraction.Cancel -> animateToResting() } } } } override fun ContentDrawScope.draw() { scale( scale = animatedScalePercent.value, pivot = currentPressPosition ) { this@draw.drawContent() } } }
ย้ายข้อมูล
ScaleIndicationเพื่อติดตั้งใช้งานIndicationNodeFactoryเนื่องจากตอนนี้เราย้ายตรรกะของคอลเล็กชันไปไว้ในโหนดแล้ว นี่จึงเป็นออบเจ็กต์ Factory ที่เรียบง่ายมาก ซึ่งมีหน้าที่เพียงอย่างเดียวคือสร้างอินสแตนซ์ของโหนดเช่น ข้อมูลโค้ดต่อไปนี้ใช้ API ที่เลิกใช้งานแล้ว
object ScaleIndication : Indication { @Composable override fun rememberUpdatedInstance(interactionSource: InteractionSource): IndicationInstance { // key the remember against interactionSource, so if it changes we create a new instance val instance = remember(interactionSource) { ScaleIndicationInstance() } LaunchedEffect(interactionSource) { interactionSource.interactions.collectLatest { interaction -> when (interaction) { is PressInteraction.Press -> instance.animateToPressed(interaction.pressPosition) is PressInteraction.Release -> instance.animateToResting() is PressInteraction.Cancel -> instance.animateToResting() } } } return instance } }
คุณควรแก้ไขข้อมูลโค้ดข้างต้นเพื่อดำเนินการต่อไปนี้
object ScaleIndicationNodeFactory : IndicationNodeFactory { override fun create(interactionSource: InteractionSource): DelegatableNode { return ScaleIndicationNode(interactionSource) } override fun hashCode(): Int = -1 override fun equals(other: Any?) = other === this }
การใช้ Indication เพื่อสร้าง IndicationInstance
ในกรณีส่วนใหญ่ คุณควรใช้ Modifier.indication เพื่อแสดง Indication สำหรับ
คอมโพเนนต์ อย่างไรก็ตาม ในกรณีที่พบได้ยากซึ่งคุณสร้าง IndicationInstance ด้วยตนเองโดยใช้ rememberUpdatedInstance คุณจะต้องอัปเดตการติดตั้งใช้งานเพื่อตรวจสอบว่า Indication เป็น IndicationNodeFactory หรือไม่ เพื่อให้คุณใช้การติดตั้งใช้งานที่เบากว่าได้ ตัวอย่างเช่น Modifier.indication จะ
มอบหมายงานภายในไปยังโหนดที่สร้างขึ้นหากเป็น IndicationNodeFactory หากไม่มี ระบบจะใช้ Modifier.composed เพื่อโทรหา rememberUpdatedInstance