Windows10 UWP开发 - 响应式设计

本篇随笔与大家简单讨论一下在开发适配不同分辨率、宽高比的Windows10 Universal App布局时的可行方式与小技巧。经验均从实践中总结,可能有诸多不完善和浅薄之处,欢迎读者严格指正。另外本文也只是抛砖引玉之用,希望能收获更多更好的实战经验。

自适配的必要性

说了这么多,我们首先可能会问了,为什么要做响应式设计?其原因有以下两点:

Windows10的跨平台性

Windows10是微软宣称可以统一运行于PC&平板&手机&Xbox等诸多平台的操作系统,当然这也是universal一词的由来。如果你希望你的应用不仅仅局限于某一个平台,那么做一些响应式布局就非常必要了。

Win10 UWP的容器窗口可自定义大小

即使你的应用仅针对windows rt的平板用户,win10对于uwp的全新处理方式也让开发者不能免于分辨率适配。下图分别是Win8.1和Win10的应用商店应用对比:
  
不难发现,为了增强store app的实用度,桌面环境下的uwp是可以自定义窗口尺寸的。为了让应用别轻易被用户玩崩坏,整理整理仪容还是相当有必要的。

废话少说,接下来,我们来看看手中能用于做响应式设计的手段吧。

自适配布局的方法

与网页设计类比

不知道读者们有多少有html+css布局经历,这一套东西尽管在布局上不算完美,但用起来也算得心应手,熟悉后能使网页布局有基本良好的适应性。
所以这里我就先说说网页前端布局与XAML布局的区别与联系吧。好消息是,一言以蔽之:几乎HTML能做的、XAML都可以。具体地说,几种在网页布局上常见手法xaml实现如下:

顺序布局

也就是没有布局咯…对于结构简单的内容呈现(比如本篇博客),用这种方式足矣。如同下面的代码模型一样

<!DOCTYPE html>
<html>
<body>
<p style="font-size:70px">I am title</p>
<div style="width:100px;height:100px;background:rgb(230,230,250);display:inline-block;"></div>
<span style="font-size:30px">Inline text</span>
<div style="font-size:32px">
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
</div>
</body>
</html>

所有的元素从上到下、左到右排列,排列不下的则进入下一行。该效果使用HTML实现非常简单,由于大部分html元素是inline的,故直接将其从上到下排列即可。

在XAML中,事情会麻烦一点,由于所有元素均不占位而浮动于界面上,故需要借助其他控件的帮助:Grid可用来从上到下安排元素,而对于同一行的元素则可以用stackpanel安排。如果需要响应度更高的布局如当宽度不够时自动换行等特性,则需配合ListView与ItemsWrapGrid进行布局。详细代码模型见下,十分简单,故不再赘述。

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Vertical" Margin="70,70,70,10">
<TextBlock Text="I am title." FontSize="70"/>
<StackPanel Orientation="Horizontal">
<Grid Background="Lavender" Width="100" Height="100"/>
<TextBlock Text="Inline text." VerticalAlignment="Bottom" FontSize="30"/>
</StackPanel>
<TextBlock Text="The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog." TextWrapping="Wrap" FontSize="32"/>
</StackPanel>
</Grid>

Absolute大法

有一种说法叫以不变应万变。
不管在什么情况下,这种布局方式是通配而普遍的:设计时固定页面尺寸,按照固定位置对每一个元素进行布局,如果框架过小则使用滚动条浏览,框架过大则自动居中。反映在html中,则是无处不在的position:absolute。
这样的优点在于方便设计,能最大程度(或者说,丝毫不差)复现designer的设计,且节省工作量(如对于电脑设计一个1366x768的布局后通用全部窗口大小)。缺点则很明显:缺乏灵活性,用户不友好,故只对于特定业务适用。

<div style="width:500px;height:500px;background:rgb(230,230,250);position:relative;">
<div style="width:130px;height:130px;background:#332CC7;position:absolute;left:20px;top:20px;">
</div>
<div style="width:310px;height:310px;background:#4CA5FF;position:absolute;left:170px;top:170px;">
</div>
<div style="width:310px;position:absolute;left:170px;top:75px;font-size:28px;">
The quick brown fox jumps over the lazy dog.
</div>
<div style="width:150px;position:absolute;left:20px;top:170px;font-size:28px;">
The quick brown fox jumps over the lazy dog.
</div>
</div>

UWP利用Canvas控件实现绝对布局,其内部元素均利用Canvas.left/Canvas.top与顶部对齐。

<Canvas Background="Lavender" Margin="70,70,70,70" Width="500" Height="500">
<Grid Background="#FF332CC7" Width="130" Height="130" Canvas.Left="20" Canvas.Top="20">
</Grid>
<TextBlock
Canvas.Top="75" Canvas.Left="170" Width="310"
Text="The quick brown fox jumps over the lazy dog. "
TextWrapping="Wrap" FontSize="28"/>
<Grid Background="#FF4CA5FF" Width="310" Height="310" Canvas.Left="170" Canvas.Top="170">
</Grid>
<TextBlock
Canvas.Top="170" Canvas.Left="20" Width="150"
Text="The quick brown fox jumps over the lazy dog. "
TextWrapping="Wrap" FontSize="28"/>
</Canvas>

流式布局

流式布局是网页设计中挺老的概念了,将布局分解成区块,区块大小与区块间距均按页面总体尺寸百分比变化,从而适应不同分辨率的窗口。而对于区块内部细节,则可根据内容和需求进行定制。
该布局方式在xaml中实现十分简单,也并非windows10的新东西,只需要在Grid的宽高定义时用*标明百分比即可。

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="90*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="5*"/>
<RowDefinition Height="90*"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<Grid Grid.Column="1" Grid.Row="1" Background="Lavender">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35*"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="64*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1" Background="White">
</Grid>
<Grid Grid.Column="2">
<Grid.RowDefinitions>
<RowDefinition Height="50*"/>
<RowDefinition Height="10"/>
<RowDefinition Height="50*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1" Background="White">
</Grid>
</Grid>
</Grid>
</Grid>

实现效果如下:

XAML独具特色的新方式

XAML自身一些具有特色的属性/控件能进一步帮忙简化响应式布局,力求做到不用代码。

Viewbox

Viewbox是一个控件,会将其容纳的对象渲染成指定的宽高,在布局很难做出改变且需要适应的变化并不大时可以使用该方法。
关于其具体使用的tips&tricks我们会另起一篇日志介绍。

Rendertransform

为UIElement的一个属性,会将对象在渲染层面按某种规则进行变化,如拉伸/翻转等。需要注意的是,所谓渲染层面,表现在与该控件有关的属性是不会察觉的:如width/height属性,将并不会知晓作用于其上的拉神操作。
如下面这段代码将伸缩Grid的宽高:

<Canvas HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Height="500" Width="450" HorizontalAlignment="Left" VerticalAlignment="Top">
<Grid.RenderTransform>
<ScaleTransform x:Name="scaler"
CenterX="0.5" CenterY="0"
ScaleX="1.3"
ScaleY="1.3"
/>
</Grid.RenderTransform>
</Grid>
</Canvas>

配合着canvas.left/top属性以及一些代码,将相当容易地自制一个viewbox。

RelativePanel+VisualStateManager

二者均为Windows10引入的新特性,前者用于允许其子元素按相对位置(附着下方、附着于上方、左右对齐等方式进行排版且在布局有变时自动调整保证其满足给定的位置关系);后者则定义多组VisualState,每一个state对应页面上不同控件的一些属性值,而在对应的state条件满足时自动将属性切换至目标值。此两点结合,将可以在很多情况下不用额外的C#代码实现响应布局。

关于此工具的具体用法,在之前发布的针对Build2015文章UWP?UWP! - Build 2015有些啥?(2)中已经提及,此处不再赘述。

Code动态调整

上面的方法都不好使?那就用code吧,麻烦是麻烦一点,其使用起来是最自由和可定制的,只要开发者心中有布局目标,就能满足一切排版需求。但是在用Code调整布局的过程中,还是有一些注意事项值得唠叨唠叨的:

事件驱动动态调整

显然,调整布局的code是事件驱动而不是一直运行的,那么写在什么事件里呢?首先大家应该能想到SizeChanged。是的,SizeChanged事件发生于对应目标的尺寸发生变化之后,也就是说,在该事件被触发时,保证能获取正确的宽高、从而根据获取到的数据进行动态布局,故将代码写进该事件是完全正确的选择。需要注意的是,位置的变化(如canvas.left值改变)不会触发该事件。另外需要注意的一点是,在事件中写入的代码不能直接/间接修改自身相关的尺寸,否则引发雪崩效应,可能带来stackoverflow。

LayoutUpdated也可以用于尺寸变化检测,但是它是一个更普遍的事件:在布局树上的元素发生改变就会触发该事件,且该事件并不指定触发对象,如果跟踪该事件将发现无论窗口发生怎么样的改变,都将触发海量的LayoutUpdated事件。故将代码写于其中并不明智。

ActualSize的获取时机

在根据尺寸动态布局的的代码中少不了获取ActualSize,但需要明确的是在布局刚做出改变时ActualSize是不会生效的,直接以该值作为基准势必导致错误。解决方案有2:1.如上文所言,将事件写于SizeChanged中,或将部分代码依赖该事件触发;2.强制调用UpdateLayout()方法,同步更新界面,从而能保证在该调用后获得的实际尺寸为真实尺寸。

总结

布局方法千千万万,本文只从最小的几个地方入手简要介绍,若需做出真正用户友好、贴近业务需求的响应式布局,还需综合应用各种布局手段,了解各手段间优劣以及其最适合的应用场景,协同作用以创造好的布局。

Windows10 UWP开发 - 响应式设计的更多相关文章

  1. Windows 10 响应式设计和设备友好的开发

    使用Effective pixels有效像素设计UI 什么是缩放像素和Effective有效像素: 当你的应用程序运行在Windows的设备,系统用一个算法控制的规范,字体,和其他UI元素显示在屏幕上 ...

  2. 纯css3开发的响应式设计动画菜单(支持ie8)

    这是一个响应式设计的菜单.单击列表图标,当你显示屏大小可以完全水平放下所有菜单项时,菜单水平显示(如图1).当你的显示屏不能水平放置所有菜单项时,菜单垂直显示(如图2). 而且显示的时候是以动画的型式 ...

  3. Grid – 入门必备!简单易懂的响应式设计指南

    如今,人们使用各种各样的移动设备访问网页,设计师们需要去适配不同的屏幕,让用户在都能有最佳的浏览体验.Grid 是一个简单的响应式设计指南,按照这些简单的步骤,你的就能够掌握基础的响应网页设计技巧. ...

  4. Bootstrap 响应式设计

    本教程讲解如何在网页布局中应用响应式设计.在课程中,您将学到响应式 Web 设计.随着移动设备的普及,如何让用户通过移动设备浏览您的网站获得良好的视觉效果,已经是一个不可避免的问题了.响应式 Web ...

  5. HTML5、CSS3响应式设计——笔记

    1.1.响应式网页设计 响应式网页设计(RWD,Responsive Web Design)这个术语,由伊桑·马科特(EthanMarcotte)提出.他在A List Apart 发表了一篇开创性的 ...

  6. paip.自适应网页设计 跟 响应式 设计的区别跟原理and实践总结

    paip.自适应网页设计 跟 响应式 设计的区别跟原理and实践总结 响应式Web设计(Responsive Web design)的理念是: 1 #-----------自适应布局VS响应式布局 2 ...

  7. web设计经验<一> 提升移动设备响应式设计的8个建议

    今天看到一些关于web设计的一些建议和设计经验,拿出来分享分享. 第一篇: 提升移动设备响应式设计的8个建议 一.直观性和易用性 在使用移动设备时,对于杂乱.复杂或者不直观的设计造成的混乱不佳的用户体 ...

  8. 超棒的响应式设计测试书签和工具(bookmarks)(转)

    一.测试书签(bookmarks) Viewport Resizer 这个书签号称拥有158个国家3万多活跃的用户,主要特性: 完全自定制 方便的添加自定义尺寸 手动的横竖屏切换 自动的横竖屏切换 ( ...

  9. 前端响应式设计中@media等的相关运用

    现在做前端响应式网站特别,响应式成为现在前端设计一个热点,它成为热点的最主要的原因就是,移动端设备屏幕的种类多样,那么如何设置响应式屏幕. /*打印样式*/ @mediaprint{color:red ...

随机推荐

  1. Python Decorator分析

    decorator本身是一个函数,这个函数的功能是接受被修饰的函数(decorated)作为参数,返回包装函数(wrapper)替换被修饰函数(decorated). @decorator func ...

  2. php设计模式 Proxy (代理模式)

    代理,指的就是一个角色代表另一个角色采取行动,就象生活中,一个红酒厂商,是不会直接把红酒零售客户的,都是通过代理来完成他的销售业务.而客户,也不用为了喝红酒而到处找工厂,他只要找到厂商在当地的代理就行 ...

  3. C++中关于文件的读写

    在C++的学习过程中,我们时常要用到对文件的操作,下面我们讲一下文件的读写. 首先,读.也就是把已有的文件读到控制台上,那么如何操作呢?首先要将文件操作的输入输出流包含进去. <fstream& ...

  4. [OSI]网络7层模型的理解

    应用层:HTTP 应用层 表现层:编码 表现层 会话层:端口 会话层 传输层:TCP/UDP 协议 传输层 网络层:IP 标记  +-- 网络层 --+  网络层 数据链路层:计算机Mac地址标记 | ...

  5. mysql 中文乱码解决方法

    最近在.NET 项目中用EF连接mysql,插入中文数据时老是显示乱码,在创建表时都已将编码指定了,但是还是出现乱码,折腾了一阵子才发现在连接字符串里面也要加上指定编码 Character Set=u ...

  6. ppt 制作海报 导出高分辨率图片

    用ppt做海报,导出图片的时候,发现导出的图片的分辨率只有96ppi,清晰度不太好. 怎么能这样呢! 网上搜了一下,发现微软提供了一个修改注册表的方法,点击这里访问.不过那里讲的最新只有2010,我的 ...

  7. Hadoop2.6.0的FileInputFormat的任务切分原理分析(即如何控制FileInputFormat的map任务数量)

    前言 首先确保已经搭建好Hadoop集群环境,可以参考<Linux下Hadoop集群环境的搭建>一文的内容.我在测试mapreduce任务时,发现相比于使用Job.setNumReduce ...

  8. LinuxMM--Memory Pressure

    Memory pressure定义在操作系统中,用户分配.文件缓存.网卡包缓冲区等等都会消耗内存.一旦出现内存紧张就会导致memory pressure.引发当某个任务需要请求内存时就有可能引发mem ...

  9. GCC4.8.2升级安装

    一.查看本机GCC版本: 使用gcc -v 查看本机版本信息,我的gcc版本为: gcc 版本 4.4.6 20120305 (Red Hat 4.4.6-4) (GCC) 二.升级或安装编译器: 1 ...

  10. SQLiteHelper

    /** * 实现对表的创建.更新.变更列名操作 * * */ public class SQLiteHelper extends SQLiteOpenHelper { public static fi ...