UWP开发入门(十四)—— UserControl中Adaptive UI的小技巧

原文: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来实现三层圆环的效果。其中三层圆环的间距通过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布局技巧的总结:

  1. 尽量不要有写死的Width和Height
  2. 可以有少量的Margin
  3. 整体为纵向布局的界面(比如手机竖着拿),横向可以有写死的数字,纵向最好按比例。反之亦然。

  

  这里还有几个问题需要说明一下:

  • 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

时间: 2024-12-24 21:35:19

UWP开发入门(十四)—— UserControl中Adaptive UI的小技巧的相关文章

Windows 8风格应用开发入门 十四 ShareContract概述及原理

Share Contract概述 我们都知道Windows 8中包含3类不同的Contract:Search Contract.Share Contract.Setting Contract.这三种Application Contract为整合Windows 8体验提供了一致性的编程模型. 现在微博,人人都是非常火的平台,我们很多人都愿意将自己所见所闻在这些平台上进行分享.在我们电脑上可能包含许多个不同的应用,包括社交类. 那么我们怎么将这些应用信息与社交类应用进行分享呢?Windows 8为我

UWP开发入门(四)——自定义CommandBar

原文:UWP开发入门(四)--自定义CommandBar 各位好,再次回到UWP开发入门系列,刚回归可能有些不适应,所以今天我们讲个简单的,自定义CommandBar,说通俗点就是自定义类似AppBarButton的东西,然后扔到CommandBar中使用. 话说为了在公司次世代平台级战略层产品上实现与水果和机器人一致的用户体验,美工把Win10 APP的AppBar也画成左右分开的了,好看是好看了,问题原生的ComandBar控件不支持这么排列啊--头疼归头疼,只能再次展开山寨之路-- 初步思

Kinect for Windows SDK开发入门(十四)进阶指引 上

前面十三篇文章介绍了Kinect SDK开发中的各个方面的最基础的知识.正如本系列博闻标题那样,这些知识只是Kinect for windows SDK开发的入门知识.本文将会介绍Kinect进阶开发需要了解一些知识(beyond the basic). 读者可能会注意到,在学习了前面十三篇文章中关于Kinect开发的方方面面,如影像数据流.景深摄像机.骨骼追踪.麦克风阵列.语音识别等这些知识后,离开发出一些我们在网上看到的那些具有良好用户体验的Kinect应用程序还是显得捉襟见肘.Kinect

UWP开发入门(十九)——10分钟学会在VS2015中使用Git

原文:UWP开发入门(十九)--10分钟学会在VS2015中使用Git 写程序必然需要版本控制,哪怕是个人项目也是必须的.我们在开发UWP APP的时候,VS2015默认提供了对微软TFS和Git的支持.考虑到现在Git很火,作为微软系的程序员也不得不学一点防身,以免被开源世界的家伙们嘲笑.蜀黍我Git也是菜鸟一只(还请老司机多多指点),只会用VS2015和SourceTree这样的GUI工具点一点按钮,但是我相信用惯了SVN和TFS的童鞋们,需要一点勇气去学习一些新东西,特别是Git已经形成潮

UWP开发入门(十五)——在FlipView中通过手势操作图片

原文:UWP开发入门(十五)--在FlipView中通过手势操作图片 本篇的最终目的,是模拟系统的照片APP可以左右滑动,缩放图片的操作.在实现的过程中,我们会逐步分析UWP编写UI的一些思路和技巧. 首先我们先实现一个横向的可以浏览图片的功能,也是大部分APP中的实现.最简单的方式是使用FlipView,再将FlipView的ItemTemplate设置成Image.大体代码如下: <FlipView ItemsSource="{Binding Photos,Mode=OneTime}&

UWP开发入门(十二)——神器Live Visual Tree

原文:UWP开发入门(十二)--神器Live Visual Tree 很久以前,我们就有Snoop这样的工具实时修改.查看正在运行的WPF程序,那时候调个样式,修改个模板,相当滋润.随着历史的车轮陷进WP的泥潭中,无论WP7的Silverlight还是WP8.1的runtime,偶们都不能方便快捷的查看APP的可视化树(Visual Tree)了,呜呼哉,是可忍孰不可忍放下筷子就骂微软.没想到Visual Studio 2015倒是给了我们一个惊喜,自带了一套非常强大的调试工具Live Visu

UWP开发入门(十)——通过继承来扩展ListView

原文:UWP开发入门(十)--通过继承来扩展ListView 本篇之所以起这样一个名字,是因为重点并非如何自定义控件,不涉及创建CustomControl和UserControl使用的Template和XAML概念.而是通过继承的方法来扩展一个现有的类,在继承的子类中增加属性和扩展行为. 我们在<UWP开发入门(七)--下拉刷新>中提到过嵌套ScrollViewer的实现思路,本篇我们对ListView的第一个扩展行为,即是摒弃嵌套的做法,而是通过访问ListView内部的ScrollView

UWP开发入门(十六)——常见的内存泄漏的原因

原文:UWP开发入门(十六)--常见的内存泄漏的原因 本篇借鉴了同事翔哥的劳动成果,在巨人的肩膀上把稿子又念了一遍. 内存泄漏的概念我这里就不说了,之前<UWP开发入门(十三)--用Diagnostic Tool检查内存泄漏>中提到过,即使有垃圾回收机制,写C#还是有可能发生内存泄漏. 一般来说,以下两种情况会导致内存泄漏: 对象用完了但是没有释放资源 对象本身是做了清理内存的操作,但是对象内部的子对象没有成功释放资源 下面就UWP开发中具体的实例来说明需要避免的写法 从static/glob

Windows 8风格应用开发入门 十九 基础控件II

Slider: Slider控件常见的效果图: 开发入门 十九 基础控件II-古诗十九首的艺术风格"> 如何在XAML代码中声明Slider控件呢?代码如下: Value属性值表示Slider控件显示的初始值,应用运行状态下我们也可以拖动改变Slider控件的值. C#代码中声明Slider控件.代码可以如下: 可以通过ValueChanged事件获取Slider控件当前的Value值 关于Slider类详细说明可以参考: Slider Class. Image: Image控件常见的效果