本篇我們通過繪制一個非常簡單的UserControl控件,來分享一下對Adaptive UI的理解及一些圖形繪制的技巧。
現在流行的APP都少不了精致的用戶頭像,首先假設我們需要繪制如下的圖形作為默認頭像:
<UserControl x:Class="AdaptiveUserControl.Circle0" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:AdaptiveUserControl" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid Width="50" Height="50" CacheMode="BitmapCache"> <Ellipse Fill="Gray"></Ellipse> <Ellipse Width="42" Height="42" Fill="White"></Ellipse> <Ellipse Width="34" Height="34" Fill="Green"></Ellipse> <TextBlock Text="F" TextAlignment="Center" VerticalAlignment="Center" TextLineBounds="Tight" Foreground="White"></TextBlock> </Grid> </UserControl>
實現較為簡單,堆疊了三個Ellipse來實現三層圓環的效果。其中三層圓環的間距通過Width和Height來實現。
通常情況下,該實現已經可以滿足我們的要求了。
再來看第二個實現:
<Grid CacheMode="BitmapCache" > <Ellipse Fill="Gray"></Ellipse> <Ellipse Margin="4" Fill="White"></Ellipse> <Ellipse Margin="8" Fill="Green"></Ellipse> <TextBlock Text="F" TextAlignment="Center" VerticalAlignment="Center" TextLineBounds="Tight" Foreground="White"></TextBlock> </Grid>
稍有不同,具體的Width和Height已經不再設置了,三層圓環的間距通過Margin來實現。
接下來看第三個實現:
<Grid CacheMode="BitmapCache"> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition Height="8*"></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition Width="8*"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <Ellipse Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="5" Grid.RowSpan="5" Fill="Gray"></Ellipse> <Ellipse Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="3" Grid.RowSpan="3" Fill="White"></Ellipse> <Ellipse Grid.Column="2" Grid.Row="2" Fill="Green"></Ellipse> <TextBlock Grid.Column="2" Grid.Row="2" Text="F" TextAlignment="Center" VerticalAlignment="Center" TextLineBounds="Tight" Foreground="White"></TextBlock> </Grid>
第三個實現已經不包含任何關於長度以及高度的數字了。所有的元素均按照比例來縮放。這樣做的好處在哪里呢。我們實際使用這三個UserControl來看看:
<Grid> <Grid.RowDefinitions> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <local:Circle0 ></local:Circle0> <local:Circle0 Grid.Column="1" Width="25" Height="25" FontSize="10"></local:Circle0> <local:Circle0 Grid.Column="2" Width="100" Height="100" FontSize="30"></local:Circle0> <local:Circle1 Grid.Row="1" Width="50" Height="50"></local:Circle1> <local:Circle1 Grid.Row="1" Grid.Column="1" Width="25" Height="25" FontSize="10"></local:Circle1> <local:Circle1 Grid.Row="1" Grid.Column="2" Width="100" Height="100" FontSize="30"></local:Circle1> <local:Circle2 Grid.Row="2" Width="50" Height="50"></local:Circle2> <local:Circle2 Grid.Row="2" Grid.Column="1" Width="25" Height="25" FontSize="10"></local:Circle2> <local:Circle2 Grid.Row="2" Grid.Column="2" Width="100" Height="100" FontSize="30"></local:Circle2> </Grid>
首先由於第一種寫法定死了Width和Height,可以看到第一排的圓形在尺寸變化時無法自適應大小,悲劇的被截斷或者無法撐開。
第二種寫法的問題在於間距被固定,雖然整體可以自動縮放,但間距仍需要通過代碼去修正才能保持比例。
第三種自然是最佳做法,無論尺寸如何變化,均可以自適應。
回顧一下之前對Adaptive Ui布局技巧的總結:
- 盡量不要有寫死的Width和Height
- 可以有少量的Margin
- 整體為縱向布局的界面(比如手機豎着拿),橫向可以有寫死的數字,縱向最好按比例。反之亦然。
這里還有幾個問題需要說明一下:
- CacheMode="BitmapCache"
堆疊的Shape圖形,我們這里是三個Circle,會導致重復的繪制影響性能。不要忘記加上CacheMode="BitmapCache"來告訴系統避免該問題。
MSDN的原文如下:
過度繪制的另一個來源是由許多重疊元素形成的形狀。 如果針對包含合成形狀的 UIElement,將 CacheMode 設置為 BitmapCache,平台會將該元素作為位圖呈現一次,然后每幀使用該位圖而不是過度繪制。
- 三種畫法的性能差距
我做了一個去除了虛擬化的ListView進行測試,各放置1000個圓形圖像。三種畫法的性能差距基本一致,沒有太大差別,請放心使用。在可以正常虛擬化的ListView中就更沒有問題了。
- 還是性能問題
非常遺憾,無論是DrawingVisual和DrawingContext這類底層的高性能的繪圖類,還是RadialGradientBrush徑向漸變的畫刷。一切可以進一步提升性能的方式,在從WPF-》Silverlight-》UWP的演化過程中,尼瑪都退化了,木有了!!!就UWP本身而言,不存在更好的繪制方式了,老老實實通過Shape來堆疊圖形吧……
最后GitHub:
https://github.com/manupstairs/UWPSamples/tree/master/UWPSamples/AdaptiveUserControl