인코더-디코더 아키텍처를 사용하는 대화형 구성요소의 컴포지션 성능을 개선하기 위해
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
를 호출합니다.