[UWP]使用CompositionAPI的翻轉動畫
1. 執行效果
在 使用GetAlphaMask和ContainerVisual製作長陰影(Long Shadow) 這篇文章裡我介紹了一個包含長陰影的番茄鍾,這個番茄鍾在狀態切換時用到了翻轉動畫,效果如上所示,還用到了彈簧動畫,可以看到翻轉後有點回彈。本來打算自己這個動畫效果寫的,但火火已經寫好了這個FlipSide
控制元件,Github地址在這裡,這篇文章就介紹下這個控制元件的部分原理。
2. TransformMatrix
Visual的 TransformMatrix 屬性是一個 Matrix4x4 的struct,它是應用於元素的轉換矩陣,可以進行動畫處理。它的預設值如下:
這時候動畫效果如下:
要使Visual可以正確旋轉需要按以下方式處理:
private void UpdateTransformMatrix(FrameworkElement element) { var host = ElementCompositionPreview.GetElementVisual(element); var size = element.RenderSize.ToVector2(); if (size.X == 0 || size.Y == 0) return; var n = -1f / size.X; Matrix4x4 perspective = new Matrix4x4( 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, n, 0.0f, 0.0f, 0.0f, 1.0f); host.TransformMatrix = Matrix4x4.CreateTranslation(-size.X / 2, -size.Y / 2, 0f) * perspective * Matrix4x4.CreateTranslation(size.X / 2, size.Y / 2, 0f); }
講真我也不明白為什麼要這麼寫,只知道是從微軟的 例子 裡抄的。每當SizeChanged事件發生時都需要呼叫這個函式重新設定TransformMatrix。
3. RotationAngleInDegrees
Visual包含兩個相似的屬性,RotationAngleInDegrees 和 RotationAngle,它們的定義如下:
// // 摘要: // 視覺物件的旋轉角度(以度為單位)。 可動畫處理。 // // 返回結果: // The rotation angle of the visual in degrees. public float RotationAngleInDegrees { get; set; } // // 摘要: // 視覺物件的旋轉角度(以弧度為單位)。 可動畫處理。 // // 返回結果: // The rotation angle in radians of the visual. public float RotationAngle { get; set; }
這兩個屬性都用於控制Visua圍繞著RotationAxis和CenterPoint旋轉。在FlipSide這個控制元件裡RotationAngleInDegrees比較適用:
float f1 = 0f, f2 = 0f;
if (IsFlipped)
{
f1 = 180f;
f2 = 360f;
VisualStateManager.GoToState(this, "Slide2", false);
}
else
{
f1 = 0f;
f2 = 180f;
VisualStateManager.GoToState(this, "Slide1", false);
}
if (springAnimation1 != null && springAnimation2 != null)
{
springAnimation1.FinalValue = f1;
springAnimation2.FinalValue = f2;
s1Visual.StartAnimation("RotationAngleInDegrees", springAnimation1);
s2Visual.StartAnimation("RotationAngleInDegrees", springAnimation2);
}
這段程式碼用到了SpringAnimatin,所以有彈一下的效果。
4. RotationAxis
RotationAxis 用於指定Visual旋轉的軸。FlipSide可以通過設定RotationAxis改變翻轉的角度,例如火火的Demo裡使用根據滑鼠改變RotationAxis:
private void OnFlipSidePointerReleased(object sender, PointerRoutedEventArgs e)
{
var position = e.GetCurrentPoint(_FlipSide).Position;
var v2 = (position.ToVector2() - _FlipSide.RenderSize.ToVector2() / 2);
_FlipSide.Axis = new Vector2(-v2.Y, v2.X);
}
5. ExpressionAnimation
<controls:FlipSide x:Name="FlipSide" IsFlipped="True">
<controls:FlipSide.Side1>
<Grid Background="#FFE87A69" x:Name="InworkElement" CornerRadius="1">
</Grid>
</controls:FlipSide.Side1>
<controls:FlipSide.Side2>
<Grid Background="#FF5271c2" x:Name="BreakElement" CornerRadius="1">
</Grid>
</controls:FlipSide.Side2>
</controls:FlipSide>
上面XAML為FlipSide的呼叫程式碼,它將Side1和Side2(這個命名超讓高達迷興奮)作為內容顯示在UI上,當IsFlipped
為False時顯示Side1的內容,當IsFlipped
為True時代表翻轉過去,此時顯示Side2的內容。在翻轉動畫的過程中,何時隱藏Side1並顯示Side2是個麻煩事。幸好UWP有強大的表示式動畫(ExpressionAnimation),FlipSide只用了下面幾句程式碼處理這個問題:
s1Visual = ElementCompositionPreview.GetElementVisual(Side1Content);
s2Visual = ElementCompositionPreview.GetElementVisual(Side2Content);
var opacity1Animation = compositor.CreateExpressionAnimation("this.Target.RotationAngleInDegrees > 90 ? 0f : 1f");
var opacity2Animation = compositor.CreateExpressionAnimation("(this.Target.RotationAngleInDegrees - 180) > 90 ? 1f : 0f");
s1Visual.StartAnimation("Opacity", opacity1Animation);
s2Visual.StartAnimation("Opacity", opacity2Animation);
這段程式碼的意思是當Side1的RotationAngleInDegrees
大於90度時隱藏,否則顯示;Side2則相反。其中,表示式中的this.Target
表示使用這個表示式動畫的Vsual。
表示式動畫的話題很大,這篇文章就割愛了,可以參考下面給出的連結瞭解更多內容:
基於關係的動畫 - Windows UWP applications Microsoft Docs
【Win 10 應用開發】UI Composition 札記(七):基於表示式的動畫 - 東邪獨孤 - 部落格園
6. 結語
感謝火火提供了這個控制元件,讓我可以省下了不少功夫。其實我對TransformMatrix真的不理解,所以這部分只是用,沒辦法詳細介紹。而且我以前對UI裡使用3D不感興趣,所以這方面真的沒法寫更多內容。期待火火為這方面補充一些部落格。
7. 參考
基於關係的動畫 - Windows UWP applications Microsoft Docs
【Win 10 應用開發】UI Composition 札記(七):基於表示式的動畫 - 東邪獨孤 - 部落格園
ExpressionAnimation Class (Windows.UI.Composition) - Windows UWP applications Microsoft Docs
Visual.TransformMatrix Property (Windows.UI.Composition) - Windows UWP applications Microsoft Docs
合成視覺物件 - Windows UWP applications Microsoft Docs
XAML 屬性動畫 - Windows UWP applications Microsoft Docs
8. 原始碼
cnbluefire_FlipSide