如要自訂共用元素轉換動畫的執行方式,可以使用一些參數來變更共用元素的轉換方式。
動畫規格
如要變更用於大小和位置移動的動畫規格,您可以在 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() 可防止在大小增加時重排。
否 |
|
|---|---|
短片和疊加
為了讓共用元素在不同的可組合項之間共用,當轉換開始到目的地中的相符項時,可組合項的算繪會提升至圖層疊加層。這樣一來,它就會超出父項的邊界和圖層轉換 (例如 Alpha 值和縮放比例)。
並在其他非共用 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。這樣做會導致項目放大或縮小。版面配置中的所有其他項目都會回應變更。
|
(請注意,清單中的其他項目會隨著該項目放大而向下移動) |
|---|---|