공유 요소 전환 애니메이션이 실행되는 방식을 맞춤설정하려면 공유 요소가 전환되는 방식을 변경하는 데 사용할 수 있는 몇 가지 매개변수가 있습니다.
애니메이션 사양
크기 및 위치 이동에 사용되는 애니메이션 사양을 변경하려면 Modifier.sharedElement()에서 다른 boundsTransform 매개변수를 지정하면 됩니다.
이렇게 하면 초기 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 사양을 사용합니다.
boundsTransform 매개변수를 보여주는 예시크기 조절 모드
두 공유 경계 간에 애니메이션을 적용할 때 resizeMode 매개변수를 RemeasureToBounds 또는 ScaleToBounds로 설정할 수 있습니다. 이 매개변수는 공유 요소가 두 상태 간에 전환되는 방식을 결정합니다. ScaleToBounds은 먼저 미리보기 (또는 타겟) 제약 조건으로 하위 레이아웃을 측정합니다. 그런 다음 하위 요소의 안정적인 레이아웃이 공유 경계에 맞게 조정됩니다.
ScaleToBounds는 상태 간의 '그래픽 배율'로 생각할 수 있습니다.
반면 RemeasureToBounds는 타겟 크기를 기반으로 애니메이션이 적용된 고정 제약 조건을 사용하여 sharedBounds의 하위 레이아웃을 다시 측정하고 다시 배치합니다. 다시 측정은 경계 크기 변경으로 인해 트리거되며, 이는 잠재적으로 모든 프레임일 수 있습니다.
Text 컴포저블의 경우 ScaleToBounds를 사용하는 것이 좋습니다. 이렇게 하면 텍스트의 레이아웃을 다시 지정하고 다른 줄로 리플로우하는 것을 방지할 수 있습니다. RemeasureToBounds는 가로세로 비율이 다른 경계에 권장되며 두 공유 요소 간에 유동적인 연속성을 원하는 경우에 권장됩니다.
두 크기 조절 모드의 차이는 다음 예시에서 확인할 수 있습니다.
|
|
|---|---|
공유 요소 동적으로 사용 설정 및 중지
기본적으로 sharedElement() 및 sharedBounds()는 대상 상태에서 일치하는 키가 발견될 때마다 레이아웃 변경사항에 애니메이션을 적용하도록 구성됩니다. 하지만 탐색 방향이나 현재 UI 상태와 같은 특정 조건에 따라 이 애니메이션을 동적으로 사용 중지해야 할 수도 있습니다.
공유 요소 전환이 발생하는지 여부를 제어하려면 rememberSharedContentState()에 전달된 SharedContentConfig를 맞춤설정하면 됩니다. isEnabled 속성은 공유 요소가 활성 상태인지 여부를 결정합니다.
다음 예에서는 특정 화면 간에 이동할 때만 공유 전환을 사용 설정하고 (예: A에서 B로만) 다른 화면에서는 사용 중지하는 구성을 정의하는 방법을 보여줍니다.
SharedTransitionLayout { val transition = updateTransition(currentState) transition.AnimatedContent { targetState -> // Create the configuration that depends on state changing. fun animationConfig() : SharedTransitionScope.SharedContentConfig { return object : SharedTransitionScope.SharedContentConfig { override val SharedTransitionScope.SharedContentState.isEnabled: Boolean // For this example, we only enable the transition in one direction // from A -> B and not the other way around. get() = transition.currentState == "A" && transition.targetState == "B" } } when (targetState) { "A" -> Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } "B" -> { Box( modifier = Modifier .sharedElement( rememberSharedContentState( key = "shared_box", config = animationConfig() ), animatedVisibilityScope = this ) // ... ) { // Your content } } } } }
기본적으로 진행 중인 애니메이션 중에 공유 요소가 사용 중지되면 진행 중인 애니메이션이 실수로 삭제되지 않도록 현재 진행 중인 애니메이션이 완료됩니다. 애니메이션이 진행되는 동안 요소를 삭제해야 하는 경우 SharedContentConfig 인터페이스에서 shouldKeepEnabledForOngoingAnimation를 재정의하여 false를 반환할 수 있습니다.
최종 레이아웃으로 건너뛰기
기본적으로 두 레이아웃 간에 전환할 때 레이아웃 크기는 시작 상태와 최종 상태 간에 애니메이션으로 표시됩니다. 이는 텍스트와 같은 콘텐츠에 애니메이션을 적용할 때 바람직하지 않은 동작일 수 있습니다.
다음 예는 설명 텍스트 'Lorem Ipsum'이 두 가지 방식으로 화면에 표시되는 것을 보여줍니다. 첫 번째 예시에서는 컨테이너 크기가 커짐에 따라 텍스트가 입력되면서 리플로우됩니다. 두 번째 예에서는 텍스트가 커져도 리플로우되지 않습니다. Modifier.skipToLookaheadSize()를 추가하면 커질 때 리플로우가 방지됩니다.
|
|
|---|---|
클립 및 오버레이
공유 요소가 여러 컴포저블 간에 공유되려면 전환이 대상의 일치 항목으로 시작될 때 컴포저블의 렌더링이 레이어 오버레이로 승격됩니다. 이렇게 하면 상위 요소의 경계와 레이어 변환 (예: 알파 및 배율)을 이스케이프합니다.
공유되지 않은 다른 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 )
공유 요소가 상위 컨테이너 외부에서 렌더링되지 않도록 하려면 sharedElement()에서 clipInOverlayDuringTransition를 설정하면 됩니다. 기본적으로 중첩된 공유 경계의 경우 clipInOverlayDuringTransition는 상위 sharedBounds()의 클립 경로를 사용합니다.
공유 요소 전환 중에 하단 바 또는 플로팅 작업 버튼과 같은 특정 UI 요소를 항상 상단에 유지하려면 Modifier.renderInSharedTransitionScopeOverlay()를 사용하세요. 기본적으로 이 수정자는 공유 전환이 활성 상태인 동안 오버레이에 콘텐츠를 유지합니다.
예를 들어 Jetsnack에서 BottomAppBar은 화면이 표시되지 않을 때까지 공유 요소 위에 배치되어야 합니다. 컴포저블에 수정자를 추가하면
컴포저블이 계속 상위로 유지됩니다
|
제공업체: |
|---|---|
공유되지 않은 컴포저블이 전환 전에 다른 컴포저블 위에 유지되면서 애니메이션으로 사라지도록 할 수 있습니다. 이러한 경우 renderInSharedTransitionScopeOverlay().animateEnterExit()를 사용하여 공유 요소 전환이 실행될 때 컴포저블을 애니메이션 처리합니다.
JetsnackBottomBar( modifier = Modifier .renderInSharedTransitionScopeOverlay( zIndexInOverlay = 1f, ) .animateEnterExit( enter = fadeIn() + slideInVertically { it }, exit = fadeOut() + slideOutVertically { it } ) )
드물지만 공유 요소를 오버레이에서 렌더링하지 않으려면 sharedElement()에서 renderInOverlayDuringTransition를 false로 설정하면 됩니다.
공유 요소 크기 변경사항을 동위 레이아웃에 알림
기본적으로 sharedBounds() 및 sharedElement()는 레이아웃 전환 시 크기 변경사항을 상위 컨테이너에 알리지 않습니다.
전환 시 크기 변경사항을 상위 컨테이너에 전파하려면 placeholderSize 매개변수를 PlaceholderSize.AnimatedSize로 변경합니다. 이렇게 하면 항목이 커지거나 작아집니다. 레이아웃의 다른 모든 항목은 변경사항에 응답합니다.
|
(한 항목이 커지면서 목록의 다른 항목이 아래로 이동하는 것을 확인합니다.) |
|---|---|