인코더-디코더 아키텍처를 사용하는 대화형 구성요소의 컴포지션 성능을 개선하기 위해
Modifier.clickable
에 새로운 API를 도입했습니다. 이러한 API를 사용하면
효율적인 Indication
구현(예: 물결 효과)
androidx.compose.foundation:foundation:1.7.0+
및
androidx.compose.material:material-ripple:1.7.0+
에는 다음 API가 포함됩니다.
변경사항:
지원 중단됨 |
대체 |
---|---|
|
|
|
대신 새로운 참고: 이 컨텍스트에서 'Material 라이브러리'는 |
|
다음 중 하나를 선택합니다.
|
이 페이지에서는 동작 변경이 미치는 영향과 새로운 API를 제공합니다.
동작 변경
다음 라이브러리 버전에는 물결 효과 동작 변경사항이 포함되어 있습니다.
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
을 설정하는 경우 자료는
구성요소는 이러한 값을 사용하지 않습니다.
다음 섹션에서는 일시적으로 이전 동작으로 돌아가는 방법을 설명합니다.
마이그레이션하지 않고 새 API로 이전하는 것이 좋습니다. 대상
이전 안내는 rememberRipple
에서 ripple
로 이전을 참고하세요.
확인할 수 있습니다.
이전 없이 Material 라이브러리 버전 업그레이드
라이브러리 버전 업그레이드를 차단 해제하려면 임시
구성할 LocalUseFallbackRippleImplementation CompositionLocal
API
Material 구성요소가 이전 동작으로 대체됩니다.
CompositionLocalProvider(LocalUseFallbackRippleImplementation provides true) { MaterialTheme { App() } }
이전 물결 효과가 발생할 수 있도록 MaterialTheme
외부에 제공해야 합니다.
LocalIndication
를 통해 제공됩니다.
다음 섹션에서는 새 API로 이전하는 방법을 설명합니다.
rememberRipple
에서 ripple
로 이전
Material 라이브러리 사용
Material 라이브러리를 사용하는 경우 rememberRipple()
을
상응하는 라이브러리에서 ripple()
호출을 삭제합니다. 이 API는 물결 효과를
Material 테마 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()
는 더 이상 구성 가능한 함수가 아니며 다음과 같을 필요가 없습니다.
있습니다. 또한 다음과 같이 여러 구성요소에서 재사용할 수 있습니다.
따라서 물결 효과 생성을 최상위 값으로 추출하여
할당을 저장합니다.
맞춤 디자인 시스템 구현
자체 디자인 시스템을 구현하며 이전에
rememberRipple()
를 맞춤 RippleTheme
와 함께 사용하여 물결 효과를 구성합니다.
대신 물결 효과 노드에 위임하는 자체 물결 효과 API를 제공해야 합니다.
material-ripple
에 노출된 API입니다. 그런 다음 구성요소가 자체 물결 효과를 사용하여
테마 값을 직접 사용합니다. 자세한 내용은 마이그레이션
제공:RippleTheme
RippleTheme
에서 이전
동작 변경을 일시적으로 선택 해제
Material 라이브러리에는 임시 CompositionLocal
가 있습니다.
LocalUseFallbackRippleImplementation
를 사용하여
Material 구성요소는 rememberRipple
사용으로 대체됩니다. 이렇게 하면
rememberRipple
는 LocalRippleTheme
를 계속 쿼리합니다.
다음 코드 스니펫은 LocalUseFallbackRippleImplementation CompositionLocal
API 사용 방법을 보여줍니다.
CompositionLocalProvider(LocalUseFallbackRippleImplementation provides true) { MaterialTheme { App() } }
Material을 기반으로 빌드된 맞춤 앱 테마를 사용 중인 경우 다음 작업을 할 수 있습니다. 앱 테마의 일부로 컴포지션 로컬을 안전하게 제공해야 합니다.
@OptIn(ExperimentalMaterialApi::class) @Composable fun MyAppTheme(content: @Composable () -> Unit) { CompositionLocalProvider(LocalUseFallbackRippleImplementation provides true) { MaterialTheme(content = content) } }
자세한 내용은 업그레이드하지 않고 Material 라이브러리 버전 업그레이드 이전 섹션을 참조하세요.
RippleTheme
를 사용하여 지정된 구성요소의 물결 효과 사용 중지
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
를 사용하여 지정된 구성요소의 물결 효과 색상/알파 변경
이전 섹션에서 설명한 것처럼 RippleConfiguration
및
LocalRippleConfiguration
는 실험용 API이며
구성요소를 맞춤설정할 수 있습니다.
예를 들어 다음 스니펫은 지원 중단된 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
를 사용하여
적용할 수 있습니다. 이는 본질적으로 커스텀 솔루션과
디자인 시스템 컴포지션 로컬 및 물결 효과. 일반적인
테마 설정 프리미티브, 이제 material-ripple
가 createRippleModifierNode()
를 노출합니다.
함수를 사용하세요. 이 함수를 사용하면 디자인 시스템 라이브러리가
테마 값을 쿼리한 다음 위임하는 wrapper
구현을 주문
물결 효과 구현을 이 함수로 만든 노드에 반환합니다.
이를 통해 디자인 시스템에서 필요한 항목을 직접 쿼리하고
상단에 사용자 구성 가능한 필수 테마 레이어가
material-ripple
레이어에서 제공되는 기능을 정의합니다. 또한 이러한 변경을 통해
물결 효과의 기본 테마/사양을 명시해야 합니다.
리플 API 자체는 명시적으로 사용되지 않습니다.
테마에서 파생됩니다.
자세한 내용은 Material의 물결 효과 API 구현을 참고하세요. 필요한 경우 머티리얼 컴포지션 로컬에 대한 호출을 자체 디자인 시스템을 구축할 수 있습니다.
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() } } }
다음 두 단계를 통해 이전할 수 있습니다.
ScaleIndicationInstance
를DrawModifierNode
로 이전합니다. API 노출 영역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
를 구현합니다. 왜냐하면 컬렉션 로직이 노드로 이동되며 이는 매우 간단한 팩토리입니다. 객체입니다.예를 들어 다음 스니펫은 지원 중단된 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
를 호출합니다.