1. WPF有,而UWP沒有的圖片平鋪功能 在WPF中只要將ImageSource的 屬性設置為 即可實現圖片的平鋪,具體可見WPF的這些文檔: "ImageBrush 類 (System.Windows.Media) _ Microsoft Docs" "TileBrush 類 (System.W ...
1. WPF有,而UWP沒有的圖片平鋪功能
在WPF中只要將ImageSource的TileMode
屬性設置為Tile
即可實現圖片的平鋪,具體可見WPF的這些文檔:
ImageBrush 類 (System.Windows.Media) _ Microsoft Docs
TileBrush 類 (System.Windows.Media) _ Microsoft Docs
TileBrush.TileMode 屬性 (System.Windows.Media) _ Microsoft Docs
WPF圖片平鋪功能我幾乎沒用過,只是作為基礎中的基礎知識記住了用法。我以為那麼基礎的功能在UWP肯定有,根本不用懷疑,所以當我在UWP中發現這麼基礎的東西居然沒有時真的嚇了一跳。
上圖左面是WPF版本的TileBrush
,右邊是UWP版本,可以看到UWP版本功能少了一大半。
這麼小的一個類,我覺得沒必要在這裡做簡化吧。幸好圖片平鋪可以使用Win2D里的BorderEffect實現。
2. UWP中的圖片平鋪功能
<Grid>
<Rectangle x:Name="Background" />
</Grid>
假設有以上的XAML,要在名為Background
的元素上應用合成畫筆,首先引用Win2D.uwp nuget包,然後參考官方文檔中 合成畫筆 的部分使用圖片創建一個合成畫筆:
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
var imageBrush = compositor.CreateSurfaceBrush();
var loadedSurface = LoadedImageSurface.StartLoadFromUri(new Uri("ms-appx:///110Strawberry.png"));
imageBrush.Surface = loadedSurface;
imageBrush.Stretch = CompositionStretch.None;
現在就差創建一個SpriteVisual
並把它應用到Background的VisualTree上了,順便一提,是這張圖片:
不過要實現平鋪功能還需要創建一個BorderEffect:
var borderEffect = new BorderEffect
{
Source = new CompositionEffectSourceParameter("source")
};
var effectFactory = compositor.CreateEffectFactory(borderEffect);
var effectBrush = effectFactory.CreateBrush();
effectBrush.SetSourceParameter("source", imageBrush);
var sprite = compositor.CreateSpriteVisual();
sprite.Brush = effectBrush;
var backgroundVisual = ElementCompositionPreview.GetElementVisual(Background);
var bindSizeAnimation = compositor.CreateExpressionAnimation("backgroundVisual.Size");
bindSizeAnimation.SetReferenceParameter("backgroundVisual", backgroundVisual);
sprite.StartAnimation("Size", bindSizeAnimation);
ElementCompositionPreview.SetElementChildVisual(Background, sprite);
總之BorderEffect
以imageBrush為Source,其它都保留預設值,將它它應用到Background的VisualTree上後效果如下:
這還不是我想要的平鋪效果。這是因為這時候ExtendX
和ExtendY
保持預設值的Clamp
,這個類型會讓BorderEffect重覆圖像邊緣的屬性。如果要實現我想要的平鋪需要將這兩個屬性設置為Wrap
:
borderEffect.ExtendX = CanvasEdgeBehavior.Wrap;
borderEffect.ExtendY = CanvasEdgeBehavior.Wrap;
居然不是從左上角開始平鋪的,和我的想法還是有出入,不過這種細節就算了。順便一提ExtendX
和ExtendY
還可以設置為Mirror
,效果如下:
3. 綁定Size
var backgroundVisual = ElementCompositionPreview.GetElementVisual(Background);
var bindSizeAnimation = compositor.CreateExpressionAnimation("backgroundVisual.Size");
bindSizeAnimation.SetReferenceParameter("backgroundVisual", backgroundVisual);
sprite.StartAnimation("Size", bindSizeAnimation);
最後順便提一下,上面的代碼中有這麼一段代碼沒介紹到,這是用來動態地設置SpriteVisual
的尺寸。ExpressionAnimation有一直運行和永不停止這兩個特性,創建ExpressionAnimation併在SpriteVisual
上運行動畫,實際上將SpriteVisual
的Size永遠地綁定為backgroundVisual 的Size的值。其實簡單地訂閱SizeChanged
事件也能達到這個效果,代碼好像還少些。
4. 結語
這麼簡單的功能居然都要這麼多代碼,或者有更簡單的實現?不過凡事都有要辯證地看,幸好它這麼複雜,又讓我水了一篇博客。
Stack Overflow有給出其它的方案,可以參考一下。
5. 參考
Border effect - Win32 apps _ Microsoft Docs
合成畫筆 - Windows UWP applications _ Microsoft Docs
【Win2D】【譯】Win2D 快速入門 - h82258652 - 博客園
基於關係的動畫 - Windows UWP applications Microsoft Docs
c# - UWP - How to tile a background image - Stack Overflow