在上一篇中,老周用一個示例,演示了框架視圖的創建過程,在本篇中,老周將給大伙伴們說一下 Composition 構建 UI 的一些“零件”。
UI Composition 有一個核心類——對,就是?Compositor 類,它是總生產車間,組成 UI 的各種元素都可以由它來創建,所以,你會看到,它公開了 K 個以 Create 開頭的方法。我們在組建 UI 時所用到的各種元素都可以調用這些以 Create 打頭的方法來創建。
要讓用戶在窗口上看到你所構建的 UI 元素,可視化樹中至少需要一 Visual 對象。Visual 是一個基類,在組成可視化樹時,我們有三種 Visual 可以用。
第一種是?ContainerVisual,它表示一容器,可以向它的?Children 集合中添加子元素,以構建復雜的可視化對象。
第二種是?SpriteVisual,它從?ContainerVisual 類派生,所以也支持添加子元素。Sprite 是“小仙女”的意思,表明這個類不僅僅是個容器,它自身就可以繪制可視化內容,所以這個類用得還是比較多的。它主要公開了 Brush 屬性,可以使用各種畫刷來繪制內容。比如,單種顏色填充的畫刷,漸變畫刷,繪制圖形的畫刷等。
第三種是 ?LayerVisual,它也是容器元素,它類似于在視圖中創建一個圖層,并可以在其中繼續添加子元素。
?
要呈現多彩燦爛的內容,你需要畫刷,因此,UI Compositon 提供各種用途的畫刷。
1、單色畫刷,只有一種顏色對對定可視化元素進行填充。
2、漸變畫刷,可以設置多種顏色過度。
3、Drawing Surface ,這個強大,相當于一塊自由畫布,你可以在上面畫各種東東。你可以畫文本,畫圓形,畫線,畫大象,畫野鴨子。甚至你可以在上面畫一個正在播放的視頻。繪制代碼是要用C++來寫,不過我們可以結合 Win 2D 組件一起用,這個老周后面會繪出例子的。
4、效果畫刷。這種畫刷主要用來產生一些視覺效果,比如模糊、銳化、顏色疊加、反相等等。
?
有了可視化對象和畫刷,我們基本上可以弄出很多東西來。不過,可能大伙伴們會想了,要是能模擬一些真實場景就更佳了。于是,燈光就出場了。燈光就是模擬我們現實世界中的各種光源,比如小燈泡發出的點光,手電筒照射的光,或者照射范圍更大的環境光(如白熾燈)等。
1、SpotLight,這種光源有點像手電筒的光,發散出去后會產生一個錐形區域。
2、PointLight,類似于一盞小燈泡,光源是一個點,但它可以向四周照射。
3、DistantLight,這種光有點像汽車的遠光燈(晚上開車時別亂開遠光啊,會害死人的),也像太陽光。總之,這種光源照射面很大,而且光很強,傳播距離遠。
4、AmbientLight,這種光就像你家里,房間里安裝的白熾燈,或者是新型的節能燈,白白的光,可以照亮整個屋子,即環境光。
老周這么一說,你一定會覺得沒意思,都不知道燈光照起來是什么效果。別急,老周后面會給例子的,你會看到效果的。
?
有刷子,有燈泡,有畫布,你大概覺得差不多了,可以畫出很多大作了。是的,不過,要是你的大作能夠動起來,是不是更生動了呢。比如你畫了豬八戒,手里拿著個大西瓜,要是能讓八戒動起來,尤其是嘴巴,一下一下地啃西瓜皮,那該多好。因此,你還需要動畫。
1、關鍵幀動畫。這個應該好懂,就是可以在某個時刻設置一個關鍵幀,然后關鍵幀之間會自動以時間為基準產生過度動畫。
2、表達式。即使用一個計算公式來生成動畫所需要的值。比如你要對可視化元素的不透明度進行動畫處理,輸入 Opacity * 0.5,表示每次的不透明度變化,最終值都是上一次計算結果的一半,比如,不透明度為 100%,進行動畫后變成 50%,再進行一次動畫后就成 25% …… 要注意的是,表達式產生的動畫是不能控制時間的。
?
以上內容你不必太認真看,就當作常識,大致涉獵一下就 OK 了,后續的博文中,老周會逐個介紹的。接下來,我們要了解一下如何構建 UI 樹。
咱們一起來動動手,學習編程一定要動手的(當然,動腦子是必須的),如果你能用腳打字,也可以動腳。
記得老周一一篇中說過的吧,我們要先實現自己的一個視圖,即實現?IFrameworkView 接口。
class DemoView : IFrameworkView {…… }
然后,我們聲明幾個私有字段。
Compositor mCompositor = null;CoreWindow mWindow = null;SpriteVisual rootVisual = null;
要組裝 UI 構件,我們需要一個?Compositor 類的實例,在這個例子中,我打算用?SpriteVisual 作為 UI 樹的根,它既可以用畫刷繪制內容,也可以添加子元素,正可謂是一物兩用。
接著,進行初始化,此時我們可以實例化 Compositor 對象,或者實例化其他我們需要的東西。注意此時不要組建 UI 樹,因為窗口還未初始化,此時建UI樹會發生異常。
public void Initialize(CoreApplicationView applicationView){mCompositor = new Compositor();}
Load方法我們這里沒啥要加載的,就留空吧。
public void Load(string entryPoint){// 留著以后用來養金魚}
接下來是重點,SetWindow 方法,此時窗口已經可用,所以此時可以組建 UI 樹了。
public void SetWindow(CoreWindow window){mWindow = window;// 創建根元素rootVisual = mCompositor.CreateSpriteVisual();// 這個是重點,必須要有這個 targetCompositionTarget target = mCompositor.CreateTargetForCurrentView();// 指定 UI 根元素target.Root = rootVisual;// 這時候UI元素上是空白的// 為了能看到東西,我們畫點東西上去CompositionColorBrush backBrush = mCompositor.CreateColorBrush(Colors.Blue);rootVisual.Brush = backBrush;}
這里有一個很重要的東東,大伙要嚴重注意。在組建 UI 時,你必須調用?CreateTargetForCurrentView 方法創建一個?CompositionTarget 實例,它直接與當前的應用程序視圖關聯的,你必須創建一個該實例,然后再把 UI 的根元素賦值給?CompositionTarget 的 Root 屬性。Root 屬性引用的UI元素就作為整個視圖的根。
而且,這個 target 在整個視圖的生命周期內,你只能創建一次,如果設置了根元素后,你還調用?CreateTargetForCurrentView 方法的話,你會收到一條?DCOMPOSITION_ERROR_WINDOW_ALREADY_COMPOSED 錯誤,該錯誤提醒你,該可視化樹已經組裝過了,你不能再調用了。
CreateColorBrush 方法創建一個單色填充的畫刷,這里我用的是藍色。
?
在 Run 方法中開啟消息循環。
public void Run(){mWindow.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit);}
但是,以上代碼漏了一句,所以一旦運行,你只能看到初始屏幕。如下圖。
因為你還沒有激活當前窗口,故你在?ProcessEvents 之前,要加上這一句。
public void Run(){mWindow.Activate(); mWindow.Dispatcher.ProcessEvents(CoreProcessEventsOption.ProcessUntilQuit);}
因為我用 mWindow 字段引用了當前窗口的實例(就是剛剛上面的 SetWindow 方法中),所以我直接調用 Activate 方法。如果你沒有用變量存儲當前窗口的實例,你還可以這樣調用。
CoreWindow.GetForCurrentThread().Activate();
?
最后,在視圖銷毀時,打掃一下衛生。
public void Uninitialize(){rootVisual.Dispose();mCompositor.Dispose();mWindow = null;}
?
視圖的邏輯弄完了,再實現一下?IFrameworkViewSource 接口。
class DemoViewSource : IFrameworkViewSource{public IFrameworkView CreateView(){return new DemoView();}}
別忘了入口點。
class Program{static void Main(){CoreApplication.Run(new DemoViewSource());}}
?
好,大功告成!按下【F5】鍵,你滿懷信心地看著程序啟動。結果傻眼了,FK!怎么一片空白的?
?
咋回事呢?是啊,咋回事呢。再檢查一下代碼,邏輯都對啊。其實,你之所以看不到東西,是因為可視化元素的大小默認是 0,所以,你要回到 SetWindow 方法,給可視化元素設一個 Size。
public void SetWindow(CoreWindow window){mWindow = window;// 創建根元素rootVisual = mCompositor.CreateSpriteVisual();rootVisual.Size = new System.Numerics.Vector2(300f, 320f); ……}
如果必要,你還可以設置視圖對象的偏移量,默認是 0、0、0,即位于窗口的左上角,注意這個坐標是三個值的,即XYZ三個軸,X和Y軸你都懂的,原點在左上角,X軸正方向往右,Y軸正方向往下。至于Z軸嘛,從屏幕里面向外,說白了就是正方向指著你。
可以設置一下偏移量。
public void SetWindow(CoreWindow window){mWindow = window;// 創建根元素rootVisual = mCompositor.CreateSpriteVisual();rootVisual.Size = new System.Numerics.Vector2(300f, 320f);rootVisual.Offset = new System.Numerics.Vector3(0f, 20f, 5f); …… }
?
?好了,一切的疑問都解開了。再運行一下,Good,效果出來了。
?
其實,你還可以讓它帶透明效果的,方法和 XAML 中一樣。
public void SetWindow(CoreWindow window){……rootVisual = mCompositor.CreateSpriteVisual();rootVisual.Size = new System.Numerics.Vector2(300f, 320f);rootVisual.Offset = new System.Numerics.Vector3(0f, 20f, 5f); rootVisual.Opacity = 0.5f; ……}
?
再看看效果。
?
?有趣吧,你還可以對它進行旋轉的。
rootVisual.RotationAngleInDegrees = 60f;
RotationAngle 屬性設置的旋轉角度是弧度角,要用角度進行設置,就用?RotationAngleInDegrees 屬性。
?
你不過癮的話,還可以調整整個三維坐標的方向。
rootVisual.Orientation = new System.Numerics.Quaternion(-15f, 5f, 2f, 1f);
?
然后就變成這個樣子了。
?
?怎么樣,有意思吧。本篇就扯到這里,大伙伴只要知道UI元素的組裝方法就可以了,至于說那些三維變量如何設置,這個可以網上查資料,或者自己摸索,三維方面的東西還是挺復雜,其實老周也不是很了解,寫出來大家交流交流而已。
?