介紹如何在Composition API中與XAML的控制元件互動以及使用基礎動畫效果。
今天要介紹的是Composition api與XAML互動的方法,說穿了也就是如何在既有的XAML Control上做些特效但使用的API非Xaml的特效。
先來個建立簡單一點的特效八~先開啟UWP專案然後在Mainpage.xaml的部分修改如下
<Page
x:Class="BasicEffectUWP.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BasicEffectUWP"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Slider x:Name="blurSilder" Header="Blur amount value" ValueChanged="Slider_ValueChanged"/>
<Grid>
<Image x:Name="targetImage" Source="ms-appx:///Assets/ninja-cat-windows-10.jpg" SizeChanged="Image_SizeChanged"/>
</Grid>
</StackPanel>
</Page>
然後在MainPage.xaml.cs的部分加入初始化Composition API的方法。
private void InitializeCompositor()
{
frameVisual = ElementCompositionPreview.GetElementVisual(Window.Current.Content);
frameCompositor = frameVisual?.Compositor;
}
來複習一下在Composition API中會一直常常需要用到的是Compositor的這個Class,這個Class就如同之前所說的是建立composition的root 所以之後的composition API會不斷使用到該class。
而這邊要介紹一個語法 ElementCompositionPreview 這個Class就是與XAML的Control作互動的Class所以只要和XAML互動的Composition就是少不了要用這個Class!這個Class提供幾個Method如下
public static Visual GetElementVisual(UIElement element);
public static Visual GetElementChildVisual(UIElement element);
public static void SetElementChildVisual(UIElement element, Visual visual);
public static CompositionPropertySet GetScrollViewerManipulationPropertySet(ScrollViewer scrollViewer);
以上的方法是從APIContract V2到V4都有支援的(也就是從10586到15063的SDK)而在V4的Contract中新增了如下的Method
public static CompositionPropertySet GetPointerPositionPropertySet(UIElement targetElement);
public static void SetImplicitHideAnimation(UIElement element, ICompositionAnimationBase animation);
public static void SetImplicitShowAnimation(UIElement element, ICompositionAnimationBase animation);
public static void SetIsTranslationEnabled(UIElement element, Boolean value);
這篇使用到的API是從API Contract V2而來的所以基本上都可以在最新的SDK實作。
剛剛上段的最後提到的這些方法中比較常用到的是GetElementVisual以及SetElementChidVisual這兩個方法!
上面這樣說的似乎會讓大家有點模糊讓我們直接看Code以及執行結果來說明會比較清楚! 剛剛XAML的部分在Image的SizeChanged的Method程式碼如下
private void Image_SizeChanged(object sender, SizeChangedEventArgs e)
{
imageRenderSize = new Vector2((float)e.NewSize.Width, (float)e.NewSize.Height);
var visual = CreateBlurEffect();
visual.Size = imageRenderSize;
ElementCompositionPreview.SetElementChildVisual(targetImage, visual);
}
這邊當Image 從Image uri或是Stream中讀取並且被decode完成後會得到實際的Render size!所以之所以會選用SizeChanged事件就是因為這樣。
然後來建立Blur的特效八~ 這邊指的Blur就是毛玻璃特效(等等API中會出現該名詞)在CreateBlurEffect的方法中加入如下的Code
private SpriteVisual CreateBlurEffect()
{
var blurEffect = new GaussianBlurEffect
{
Name = "Blur",
BlurAmount = blurAmount,
Source = new CompositionEffectSourceParameter("BackDrop"),
BorderMode = EffectBorderMode.Hard
};
var factory = frameCompositor?.CreateEffectFactory(blurEffect, new List<string> { "Blur.BlurAmount" });
brush = factory?.CreateBrush();
var dropBrush = frameCompositor?.CreateBackdropBrush();
brush.SetSourceParameter("BackDrop", dropBrush);
var blurSprite = frameCompositor?.CreateSpriteVisual();
blurSprite.Brush = brush;
return blurSprite;
}
這邊需要注意的是....GaussianBlurEffect是在Win2D的Nuget package中喔!所以記得先去Nuget 中加入Win2D.uwp的參考!這邊GaussianBlurEffect是產生毛玻璃特效非常有效的物件!因為Win2D就是把DirectX 2D的需多功能簡化給UWP以及Store app使用~
最後藉由compositor產生出SpriteVisual,並且把SpriteVisual的Brush替換掉之後拋出去給Image_SizeChanged的程式碼片段,然後再把該Visual的Size做更新(與圖片相符的Size)最後再由SetElementChildVisual的方法把Visual放入XAML tree之中。
SpriteVisual是蠻基礎型別使用的Visual因為這個物件繼承了ContainerVisual所以可以這個Visual可以是個Visual的容器且該Visual是專門處理2D平面。
最後來把xaml上的slider的ValueChanged的Method的Code補上八
float blurAmount => (float)blurSilder.Value;
private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
brush.Properties.InsertScalar("Blur.BlurAmount", blurAmount);
}
這邊是建立一global的parameter 命名為blurAmount然後再Slider的ValueChanged的時候會再對SpriteVisual使用的Brush內使用到的GaussianBlurEffect的參數做更新!
整個MainPage.xaml.cs的程式碼如下
public sealed partial class MainPage : Page
{
Visual frameVisual;
Compositor frameCompositor;
CompositionEffectBrush brush;
Vector2 imageRenderSize;
float blurAmount => (float)blurSilder.Value;
public MainPage()
{
this.InitializeComponent();
InitializeCompositor();
}
private void InitializeCompositor()
{
frameVisual = ElementCompositionPreview.GetElementVisual(Window.Current.Content);
frameCompositor = frameVisual?.Compositor;
}
private SpriteVisual CreateBlurEffect()
{
var blurEffect = new GaussianBlurEffect
{
Name = "Blur",
BlurAmount = blurAmount,
Source = new CompositionEffectSourceParameter("BackDrop"),
BorderMode = EffectBorderMode.Hard
};
var factory = frameCompositor?.CreateEffectFactory(blurEffect, new List<string> { "Blur.BlurAmount" });
brush = factory?.CreateBrush();
var dropBrush = frameCompositor?.CreateBackdropBrush();
brush.SetSourceParameter("BackDrop", dropBrush);
var blurSprite = frameCompositor?.CreateSpriteVisual();
blurSprite.Brush = brush;
return blurSprite;
}
private void Slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
brush.Properties.InsertScalar("Blur.BlurAmount", blurAmount);
}
private void Image_SizeChanged(object sender, SizeChangedEventArgs e)
{
imageRenderSize = new Vector2((float)e.NewSize.Width, (float)e.NewSize.Height);
var visual = CreateBlurEffect();
visual.Size = imageRenderSize;
ElementCompositionPreview.SetElementChildVisual(targetImage, visual);
}
}
最後來看看執行結果八
當Silder的Value為0的圖片效果並沒有毛玻璃特效
當Value拉到50的時候
拉到100的時候~基本上已經看不出甚麼東西啦~~
總結
這篇主要講到的是最常使用到的與Xaml control互動需要的API以及基礎的特效。後須第三篇會把這個基礎特效的部分補齊。
***以上Code以及說明以都有可能隨著Windows 10 的版本以及Visual Studio 版本有所調整!***
參考資料 MSDN
下次再分享Windows 10 的新技術拉~