[UWP]使用CompositionAPI的翻轉動畫

  • 2019 年 11 月 14 日
  • 筆記

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包含兩個相似的屬性,RotationAngleInDegreesRotationAngle,它們的定義如下:

//  // 摘要:  //     視覺對象的旋轉角度(以度為單位)。 可動畫處理。  //  // 返回結果:  //     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