[譯]理解 Windows UI 動畫引擎

来源:http://www.cnblogs.com/validvoid/archive/2016/04/08/understand-whats-possible-with-the-windows-ui-animation-engine.html
-Advertisement-
Play Games

本文譯自 Nick Waggoner 的 "Understand what’s possible with the Windows UI Animation Engine",已獲原作者授權進行翻譯。更多有關 Windows UI、UWP 開發的文章,歡迎訪問我的博客源站:http://validvo ...


本文譯自 Nick Waggoner 的 "Understand what’s possible with the Windows UI Animation Engine",已獲原作者授權進行翻譯。更多有關 Windows UI、UWP 開發的文章,歡迎訪問我的博客源站:http://validvoid.net/


2015 年 11 月,視覺層 (Visual Layer)作為 Windows.UI.Composition 命名空間中的一系列新 API 被引入。這些新 API 標志著開發者首次有機會接觸那些支撐著自 Windows 8 以來各種 UI 框架(例如 IE/Edge、XAML 和 Windows Shell)的功能特性。全新視覺層的一個重要方面就是其動畫引擎。但今年在 //build/ 大會上為開發者進行大量講談之後,我發現開發者們任然不太清楚動畫系統的各部分是如何協同工作的。為了幫助你理解動畫系統的潛力,我們通過兩個問題進行理解:

  • 誰負責開始動畫?
  • 什麼驅動動畫,改變取值?

隱式 vs. 顯式 – 誰負責開始動畫?

顯式動畫和隱式動畫之間的關鍵區別就在於誰負責觸發動畫。

長話短說:顯式動畫你觸發;隱式動畫你配置。

顯式動畫

提到動畫,大部分人想到的都是顯式動畫,對此你應該很熟悉了。對於顯式動畫,你進行設置之後,也由作為開發者你的自己進行觸發。

例如,在 XAML 中通常用標記語言創建動畫,在後臺代碼中觸發動畫。

標記語言代碼:

<Storyboard x:Name="myStoryboard">  
    <DoubleAnimation From="1" To="6" Duration="00:00:6" 
                     Storyboard.TargetName="rectScaleTransform" 
                     Storyboard.TargetProperty="ScaleY">
        <DoubleAnimation.EasingFunction>
            <BounceEase Bounces="2" EasingMode="EaseOut" 
                        Bounciness="2" />
        </DoubleAnimation.EasingFunction>
    </DoubleAnimation>
</Storyboard>  

 

後臺代碼:

private void OnButtonClick(object sender, RoutedEventArgs e)  
{
    myStoryboard.Begin();
}

 

視覺層中的動畫系統同樣也支持顯式動畫——儘管只在你的後臺代碼中。這使你能取用已知動畫配置並直接使用。

後臺代碼:

// 獲取表示此 UIElement 的 Visual (視覺元素對象)並從中獲取 compositor (合成器對象)
Visual tempVisual = ElementCompositionPreview.GetElementVisual(this);  
Compositor compositor = tempVisual.Compositor;

// 創建一個簡單的 ScalarKeyFrameAnimation (標量關鍵幀動畫)
ScalarKeyFrameAnimation scalarAnimation = compositor.CreateScalarKeyFrameAnimation();  
scalarAnimation.Duration = TimeSpan.FromMilliseconds(300);  
scalarAnimation.InsertKeyFrame(1f, 200f);

// 顯式開始動畫
tempVisual.StartAnimation("Offset.X", scalarAnimation);  

 

以上例子的模式都是相同的。你先定義動畫(也就是動畫的時長、運動軌跡、目標屬性以及取值),然後通過 start/begin 方法顯式觸發動畫。

隱式動畫

相對於顯式動畫,隱式動畫則是由平臺觸發的。例如,下列代碼演示瞭如何在 XAML 中為一個按鈕附加 EntranceThemeTransition

<Button Content="EntranceThemeTransition Button">  
    <Button.Transitions>
        <TransitionCollection>
            <EntranceThemeTransition />
        </TransitionCollection>
    </Button.Transitions>
</Button>  

 

這就是實現效果所需的全部代碼。當按鈕初次呈現時,它會觸發 EntranceThemeTransition,使其以動畫形式運動到目標位置。在視覺層出現之前,你只有屈指可數的幾個隱式動畫可供選擇,也就是 XAML 過渡效果動畫 (the XAML Transitions),並且幾乎無法對其進行配置。而視覺層不僅支持隱式動畫,還給了你更大的定製空間:

// 創建一個映射表用於儲存觸發器/動畫配對。
ImplicitAnimationMap implicitAnimationCollection = _compositor.CreateImplicitAnimationMap(); 

// 創建實際要運行的動畫。
var _offsetKeyFrameAnimation = _compositor.CreateVector3KeyFrameAnimation();  
_offsetKeyFrameAnimation.InsertExpressionKeyFrame(1.0f, "this.FinalValue");  
_offsetKeyFrameAnimation.Duration = TimeSpan.FromSeconds(3); 

// 設置當 Offest(觸發器) 改變時要運行的動畫。
implicitAnimationCollection["Offset"] = _offsetKeyFrameAnimation; 

// 應用隱式動畫。
myVisual.ImplicitAnimations = implicitAnimationCollection;  

 

根據這段代碼,無論何時只要 myVisual 的 Offset 發生改變,_offsetKeyFrameAnimation 都會被平臺觸發。註意在這一隱式動畫的定義中用到了一個 ExpressionKeyFrame,也就是表達式關鍵幀。表達式關鍵幀允許你設置數學表達式,動畫系統在播放表達式動畫 (ExpressionAnimations)的每一幀時都會計算此表達式的值。在我們的例子里,我們使用了一個簡單的表達式 this.FinalValue,只是對觸發動畫的條件進行取值。這一動畫只是一個非常基本的示例,但通過表達式你能定義任何你想要的動畫。

視覺層隱式動畫的靈活性使得你能夠將應用的邏輯與動效分離,並提供了一種強大的方式定製你的體驗。例如,隱式動畫一種不錯的用法就是對 "Offset" 設置觸發器,這樣你就能創建從一種佈局向另一種佈局動畫過渡的效果,並且該效果是由 XAML 的佈局引擎自動觸發的。

想要深入瞭解隱式動畫,//build/ 大會上的這一講談節目是個不錯的起點。

專業利器 – 什麼驅動動畫?

時間驅動動畫

時間驅動動畫是開發者們熟知並且喜愛的經典動畫類型。上文中的代碼片段展示了 XAML 的 storyboard 動畫以及 composition 的關鍵幀動畫,它們都是時間驅動型動畫。關鍵幀動畫背後的思想(實際上是標準)就是你為特定時間的動畫都指定目標取值,並描述這些取值之間如何過渡(通常成為插值或緩動函數)。XAML 提供了一大批內建的緩動函數幫助你輕鬆實現美觀的動效。而在視覺層中,負責提供緩動動效的則是CubicBezierEasingFunction 類(意為三次貝塞爾緩動函數)。CubicBezierEasingFunction 通過兩個控制點控制運動軌跡。控制點允許你以細粒度方式控制插值。而且鑒於各類動畫引擎中廣泛使用貝塞爾曲線描述緩動,你能輕鬆獲得很多效果不錯的預定義控制點方案。我通常使用 Easings.net 獲取標準平納緩動函數1的控制點。

引用驅動動畫(數學驅動)

在 Windows 10 的 10586 十一月更新中,ExpressionAnimation (表達式動畫)被引入視覺層的動畫引擎。表達式動畫允許你在動畫系統中創建屬性之間在幀間更新的數學關係。視差動畫就是一個經典的表達式動畫:

// 創建驅動視差動畫的表達式。
ExpressionAnimation parallaxAnimation = compositor.CreateExpressionAnimation("MyForeground.Offset.Y / MyParallaxRatio");

// 設置我們希望背景進行視差滾動的速度。
parallaxAnimation.SetScalarParameter("MyParallaxRatio", 0.5f);

// 設置前景對象的引用。
parallaxAnimation.SetReferenceParameter("MyForeground", foregroundVisual);

// 在背景對象上開始動畫。
backgroundVisual.StartAnimation("Offset.Y", parallaxAnimation);  

 

這段代碼所做的第一件事是創建一個用於描述一些輸入與動畫結果輸出之間關係的數學表達式。表達式中定義了幾個參數和稍後賦值的引用。參數幫助你配置數學關係,但引用才是使表達式靈動的重點。一個參數(例如 MyParallaxRatio)是通過調用指定類型的函數(例如 SetScalarParameter)賦值的。此行為通知動畫引擎對該參數的所有實例以你傳入的取值進行求值。求值動作只在將動畫交由引擎處理前發生一次,因此這是一個指定常量取值的好辦法。相反,一個引用(例如 MyForeground) 則是動畫引擎在每幀求值的。這正是實際使表達式動畫靈動的魔法所在。

此外還有兩點需要指出。首先,你會註意到我們能夠訪問 MyForeground 的成員以及 Y子通道。表達式的語法允許訪問成員以及“混合”或交換一個矢量/矩陣的成分。例如:

// 重用 offset 的 X 通道創建一個 Vector2 動畫。
ExpressionAnimation vector2Animation = compositor.CreateExpressionAnimation("MyForeground.Offset.X");

// 設置對前景對象的引用。
vector2Animation.SetReferenceParameter("MyForeground", foregroundVisual);  

 

另一點需要指出的是,視覺層中的所有動畫實際上都是模板。這意味著你可以對多個對象使用同一個動畫或重用動畫的結構,只在下一個對象的動畫開始前更新參數和引用。例如,如果我們想要擴展基本視差動畫,添加多層景深效果,我們可以只需要一個動畫定義即可:

// 創建驅動視差滾動的表達式動畫。
ExpressionAnimation parallaxAnimation = compositor.CreateExpressionAnimation("MyForeground.Offset.Y / MyParallaxRatio");

// 設置前景對象引用。
parallaxAnimation.SetReferenceParameter("MyForeground", foregroundVisual);

// 設置背景對象視差滾動速度。
parallaxAnimation.SetScalarParameter("MyParallaxRatio", 0.5f);

// 對背景對象開始動畫。
backgroundVisual.StartAnimation("Offset.Y", parallaxAnimation);


// 設置遠距背景對象的視差滾動速度。
parallaxAnimation.SetScalarParameter("MyParallaxRatio", 0.2f);

// 對遠距背景對象開始動畫。
deepBackgroundVisual.StartAnimation("Offset.Y", parallaxAnimation); 

 

表達式動畫是一種全新而強大的動畫方式,使我們能藉以表示物體如何相對運動。表達式動畫為我們免去了設置一系列複雜動畫的痛苦,使多個不同對象和屬性協同運動因而變得更加容易。要深入瞭解表達式動畫,可參見 //build/ 講談:

P486: Using Expression Animations to Create Engaging & Custom UI

輸入驅動動畫

自大約五年前觸摸漸成主流起,創造低延遲體驗成為了一種普遍需求。使用手指或筆在屏幕上操作,使得人眼獲得了更直觀的參照點來辨識操作的延遲和流暢性。為使操作流暢,主流操作系統公司均將更多的操作移交至系統和 GPU (如 ChromeIE)執行。在 Windows 上,這由 DirectManipulation 這一或多或少是針對於觸摸構建的動畫引擎實現的。它解決了關鍵的延遲挑戰,也就是如何自然地以展示從輸入驅動到事件驅動過渡的動效。但另一方面,它也幾乎沒有提供對定製慣性觀感的支持,就像福特 T 型車那樣——“只要車是黑色的,你可以把它塗成任意你喜歡的顏色”。2

ElementCompositionPreview.GetScrollViewerManipulationPropertySet 是讓你能夠把玩輸入驅動動效的第一步。雖然它仍然沒給你任何對內容滾動時觀感進行控制的額外能力,但它確實允許你對次級內容應用表達式動畫。例如,我們終於能完成我們的基礎視差滾動代碼:

// 創建驅動視差滾動的表達式動畫。
ExpressionAnimation parallaxAnimation = compositor.CreateExpressionAnimation("MyForeground.Offset.Y / MyParallaxRatio");

// 設置對前景對象的引用。
CompositionPropertySet MyPropertySet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(MyScrollViewer);  
parallaxAnimation.SetReferenceParameter("MyForeground", MyPropertySet);

// 設置背景對象視差滾動的速度。
parallaxAnimation.SetScalarParameter("MyParallaxRatio", 0.5f);

// 對背景對象開始視差動畫。
backgroundVisual.StartAnimation("Offset.Y", parallaxAnimation);  

 

使用這一技巧,你能夠實現多種優秀的效果:視差滾動、粘性表頭、自定義滾動條等等。唯一缺失的就是定製操作本身的觀感……

再來看看 InteractionTracker。這一全新設計的特性在給予你控制操作觀感方方面面的靈活性的同時,保證了手指操作低延遲的體驗。在 Windows 的 UI 平臺上,我們時常談到便利性與和可行性之間的權衡。常規 UX 和調用模式通常被包裝成簡單易用的高級控制項和特性。這確實使得他們簡單易用,但也在一定程度上損失了靈活操控性。而尺度的另一端則是如圖形層(Graphics Layer) 的這類封裝。它們使你能夠完全控制每個像素在屏幕上的呈現,但也帶來了更大的複雜性。在輸入處理的設計中,InteractionTracker 更多地傾向於可行性這一側。如今在 Windows UI 平臺上,你首次能夠描述性地將輸入到輸出映射為具體的動效。

這裡我們以一個簡單的示例,通過修改慣性結束的位置來演示這種全新的靈活性。過去,你通過指定四種 對齊點(Snap-points) 類型中的一種來修改 XAML 中 ScrollViewer 的慣性表現。現在,有了 InteractionTracker提供的更多種可能性,你可以使用表達式動畫來定義慣性在哪結束。下麵是一個例子,基於慣性自然停止的位置創建了三種不同的對齊點方案:

// 創建一個慣性端點,其條件與結束點在面板近側。
// 變數在稍後公有變數更新後填入。
var snapNearConditionExpression =     s_compositor.CreateExpressionAnimation("target.Position.X < - target.CompletionThreshold");  
var snapNearValueExpression = s_compositor.CreateExpressionAnimation("-target.CompletedOffset");

var snapNearEndpoint = InteractionTrackerInertiaRestingValue.Create(s_compositor);  
snapNearEndpoint.Condition = snapNearConditionExpression;  
snapNearEndpoint.RestingValue = snapNearValueExpression;

// 創建一個慣性端點,其條件與結束點在面板遠側。
// 變數在稍後公有變數更新後填入。
var snapFarConditionExpression = s_compositor.CreateExpressionAnimation("target.Position.X > target.CompletionThreshold");  
var snapFarValueExpression = s_compositor.CreateExpressionAnimation("target.CompletedOffset");

var snapFarEndpoint = InteractionTrackerInertiaRestingValue.Create(s_compositor);  
snapFarEndpoint.Condition = snapFarConditionExpression;  
snapFarEndpoint.RestingValue = snapFarValueExpression;

// 創建一個總慣性控制端點,用於控制如果沒有其它慣性修改器生效則歸為至靜息狀態。
var snapHomeEndpoint = InteractionTrackerInertiaRestingValue.Create(s_compositor);  
snapHomeEndpoint.Condition = s_compositor.CreateExpressionAnimation("true");  
snapHomeEndpoint.RestingValue = s_compositor.CreateExpressionAnimation("0");

// 插入慣性端點表達式引用的屬性。
s_interactionTracker.Properties.InsertScalar(nameof(CompletedOffset), (float)m_completedOffset);  
s_interactionTracker.Properties.InsertScalar(nameof(CompletionThreshold), (float)m_completionThreshold);  
s_interactionTracker.ConfigurePositionXInertiaModifiers(  
new InteractionTrackerInertiaModifier[] { snapNearEndpoint, snapFarEndpoint, snapHomeEndpoint });  

 

實際上你不僅能夠如示例中一樣修改慣性結束的位置,還能夠修改慣性動效的軌跡。InteractionTracker 使你能夠精准定制出體現標誌性體驗的觀感。要瞭解更多有關 InteractionTracker 潛力與使用的內容,可參見:

P405: Adding Manipulations in the Visual Layer to Create Customized & Responsive Interactive Experiences

如何進一步深入?

如果你還未查看 WindowsUIDevLabs 代碼倉庫,你絕對應該馬上去看看。該倉庫的簡介是這樣的:

歡迎來到 Windows UI 開發實驗室的代碼倉庫,本庫包含了最新的示例代碼、示例項目以及來自使用 Windows UI 開發各種精美 UWP 應用的開發者的反饋。

作為深入理解學習 Windows UI 的下一站,該代碼倉庫是獲取深入理解平臺與各種協助代碼的好地方。


譯者註:

  1. 平納緩動函數(Penner’s Easing Functions):由 Robert Penner 定義的一組流行的緩動函數,被各種動效實現廣泛使用。 

  2. 福特 T 型車是福特於1908年至1927年推出的一款價格低廉廣受歡迎的汽車。福特在其自傳第四捲中提到他曾對銷售人員說“只要車是黑色的,顧客可以把它塗成任何自己喜歡的顏色。”由於黑色塗料廉價耐用,出於提高生產效率的考慮福特作出了只出產黑色車型的決定。但這一決定使得福特後續的份額被競爭對手蠶食。 


關於作者

本文原作者 Nick Waggoner 供職於微軟 native Windows UI platform(@WindowsUI)。

原作者博客:http://www.nickwaggoner.com/www.nickwaggoner.com/

原作者 Twitter:@nrwaggs

本文已獲原作者授權進行翻譯。我後續會持續翻譯 Nick Waggoner 在個人博客或其它位置發表的有關 UWP、 Windows UI 的文章。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • sar -n DEV 1 100 1代表一秒統計並顯示一次 100代表統計一百次 使用ntop等工具,就更方便簡單了,不過這個更靈活 P.S. sar在sysstat包 來源:http://www.cnblogs.com/eshizhan/archive/2012/04/11/2441644.htm ...
  • dhcp伺服器是pxe自動化安裝的必要條件,因此先搞定dhcp伺服器,yum -y install dhcp, rpm -ql dhcp查看安裝了哪些包,less /etc/dhcp/dhcpd.conf 打開dhcp的主配置文件,如下圖: 沒有任何配置,但提示了去哪找主配置文件,cp /usr/s ...
  • (1)需要指定一下hwaddr(2)onboot=yes/etc/sysconfig/network-script/ ...
  • win10 ,本地連接無法識別網路 ,無線正常, 電腦診斷是:“此電腦上缺少一個或者多個網路協議” 1.手動設置ip 失敗 2.網卡卸載驅動 再安裝 失敗 3.網卡驅動更新 失敗 4.重置ie”高級設置 “ 附帶“刪除個性化” 附帶“ 退出電腦管家 ” 失敗 why... why... why.. ...
  • 很多項目使用的系統是centos或者redhat,最近有一個項目使用的系統竟然是阿裡雲unbantu,不知道他們負責人怎麼想的,明明有centos,非要用unbantu。抱怨到此,unbantu的學習是不可避免了,下麵開始記錄學習unbantu過程,持續更新。 1.首先學習如何安裝程式 可以看這個鏈 ...
  • sort命令 sort:文本排序,僅僅是對顯示文件的排序,而不影響源文件的順序,是根據ASSII碼 的字元升序來排列的。 -n:安裝數值大小從小到大排列 ,預設是升序。 -r:降序排列 ***** -t:指定欄位分隔符,表示按點號分隔域(類似awk -F,取欄位用$1,$2或cut的-d,取欄位f數 ...
  • uniq命令: 常見參數: -c,--count ***** 在每行旁邊顯示改行重覆出現的次數 -d,--repeated 僅顯示重覆出現的行,2次或2次以上的行,預設的去重包含1次。 例子: a.只對相鄰的相同行內容去重。 [root@nfs-server test]# cat test.txt ...
  • 恢復內容開始 最近看了園子里的大神分享的springnet框架的知識,感覺挺不錯的,自己閑下來也研究研究springnet。這幾天看了springnet容器的基礎篇IOC和AOP,也有點個人理解分享一下,記錄一下自己的學習筆記,歡迎大家提出問題一塊研究解決。 入門springnet首先瞭解一下什麼是 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...