UWP開發入門(十四)—— UserControl中Adaptive UI的小技巧


  本篇我們通過繪制一個非常簡單的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來實現三層圓環的效果。其中三層圓環的間距通過WidthHeight來實現。

  通常情況下,該實現已經可以滿足我們的要求了。

  再來看第二個實現:

    <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>

  稍有不同,具體的WidthHeight已經不再設置了,三層圓環的間距通過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>

   首先由於第一種寫法定死了WidthHeight,可以看到第一排的圓形在尺寸變化時無法自適應大小,悲劇的被截斷或者無法撐開。

  第二種寫法的問題在於間距被固定,雖然整體可以自動縮放,但間距仍需要通過代碼去修正才能保持比例。

  第三種自然是最佳做法,無論尺寸如何變化,均可以自適應。

 

  回顧一下之前對Adaptive Ui布局技巧的總結:

  1. 盡量不要有寫死的WidthHeight
  2. 可以有少量的Margin
  3. 整體為縱向布局的界面(比如手機豎着拿),橫向可以有寫死的數字,縱向最好按比例。反之亦然。

  

  這里還有幾個問題需要說明一下:

  • CacheMode="BitmapCache"

  堆疊的Shape圖形,我們這里是三個Circle,會導致重復的繪制影響性能。不要忘記加上CacheMode="BitmapCache"來告訴系統避免該問題。

  MSDN的原文如下:

  過度繪制的另一個來源是由許多重疊元素形成的形狀。 如果針對包含合成形狀的 UIElement,將 CacheMode 設置為 BitmapCache,平台會將該元素作為位圖呈現一次,然后每幀使用該位圖而不是過度繪制。

  • 三種畫法的性能差距

  我做了一個去除了虛擬化的ListView進行測試,各放置1000個圓形圖像。三種畫法的性能差距基本一致,沒有太大差別,請放心使用。在可以正常虛擬化的ListView中就更沒有問題了。

  • 還是性能問題

  非常遺憾,無論是DrawingVisualDrawingContext這類底層的高性能的繪圖類,還是RadialGradientBrush徑向漸變的畫刷。一切可以進一步提升性能的方式,在從WPF-Silverlight-UWP的演化過程中,尼瑪都退化了,木有了!!!就UWP本身而言,不存在更好的繪制方式了,老老實實通過Shape來堆疊圖形吧……

 

  最后GitHub:

  https://github.com/manupstairs/UWPSamples/tree/master/UWPSamples/AdaptiveUserControl


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM