如要自訂共用元素轉換動畫的執行方式,可以使用幾個參數變更共用元素的轉換方式。
動畫規格
如要變更大小和位置動作使用的動畫規格,您可以在 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
規格。
調整大小模式
在兩個共用邊界之間建立動畫時,您可以將 resizeMode
參數設為 RemeasureToBounds
或 ScaleToBounds
。這個參數可決定共用元素在兩種狀態之間轉換的方式。ScaleToBounds
會先使用 Look 圖表 (或目標) 限制條件測量子版面配置。接著,系統會將子項的穩定版面配置調整為符合共用邊界。ScaleToBounds
可視為是兩個狀態之間的「圖形比例」。
而 RemeasureToBounds
會重新測量及重新配置 sharedBounds
的子版面配置,而會根據目標大小,使用固定的動畫限制動畫。重新測量作業是由邊界大小變更觸發,可能代表每個影格。
針對 Text
可組合項,建議使用 ScaleToBounds
,因為這樣可避免將文字重新安排到不同的行。針對不同長寬比的邊界,且如果您希望兩個共用元素之間的一致性,建議使用 RemeasureToBounds
。
您可在以下範例中瞭解兩種調整大小模式的差異:
|
|
---|---|
跳至最終版面配置
根據預設,在兩個版面配置之間切換時,版面配置大小會在開始和最終狀態之間進行動畫。在為文字等內容建立動畫時,這可能會是不理想的行為。
以下範例說明「Lorem Ipsum」以兩種不同方式輸入畫面的說明文字。第一個範例會在容器放大時的文字自動重排,第二個範例在容器放大時不會重排。新增 Modifier.skipToLookaheadSize()
即可避免在增加時自動執行自動重排。
沒有 Modifier.skipToLookahead() - 請留意「Lorem Ipsum」文字重排 |
Modifier.skipToLookahead() - 請注意,「Lorem Ipsum」文字會在動畫開始時保留最終狀態 |
---|---|
剪輯片段和疊加層
在 Compose 中建立共用元素時,一個重要概念,是為了讓這些元素在不同可組合項之間共用,當轉換開始讓其與目的地相符時,可組合項的算繪作業會提升至圖層疊加層。這種做法會逸出父項的邊界及其圖層轉換 (例如 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
。這樣會導致項目成長或縮小。版面配置中的所有其他項目都會回應變更。
|
(請注意,清單中其他項目如何隨著某個項目逐漸增加而下移) |
---|---|