1. 程式人生 > >[UWP]使用CompositionAPI的翻轉動畫

[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