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. 关于delphi点击webbrowser中任意一点的问题

    关于delphi点击webbrowser中任意一点的问题 有时候我们需要delphi载入webbrowser1打开网页的时候 需要点击某一个点的位置 可能是坐标 可能是按钮 可能是其他的控件应该如何来 ...

  2. DSP(1) -- 离散时间信号的序列类型

    1.单位采样序列δ(n):在MATLAB 中函数zeros(1,N)产生一个由N个零组成的列向量.它可用来实现有限区间的δ(n).然而,更高明的方法是利用逻辑关系式n==0来实现δ(n). 2.单位阶 ...

  3. 数据库.bak文件还原报错的处理办法

    今天从网上下了个Demo,里面有个.bak文件,就试着还原了一下,结果发现报了错.是了两种方式导入,都不行. 最终找到了解决办法: 可以直接用sql语句对.bak文件进行还原. RESTORE DAT ...

  4. 【Mail】JavaMail介绍及发送邮件(一)

    JavaMail介绍 JavaMail是SUN提供给开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发类库,支持常用的邮件协议,如SMTP.POP3.IMAP,开发人员使用JavaMail ...

  5. java反射案例

     Java反射经典实例 2007-08-29 17:55:25 分类: Java Java提供了一套机制来动态执行方法和构造方法,以及数组操作等,这套机制就叫——反射.反射机制是如今很多流行框架的实现 ...

  6. oc数据类型

    数据类型:基本数据类型.指针数据类型 基本数据类型:数值型.字符型(char).布尔型.空类型(void)指针数据类型:类(class).id数值型:整数类型int.浮点型float.doublec和 ...

  7. DLX (poj 3074)

    题目:Sudoku 匪夷所思的方法,匪夷所思的速度!!! https://github.com/ttlast/ACM/blob/master/Dancing%20Link%20DLX/poj%2030 ...

  8. 为什么LTE系统的最小时间单位是Ts?

    之前一直在做LTE物理层相关的工作,一直有个疑惑, 在36.211开头的一章定义Ts的大小是1/(15000*2048)s,为什么定义这么一个奇怪的unit time. 最近才反应过来,这跟FFT/I ...

  9. 在Windows server 2008 R2上安装Python3.5

    最近弄了台机器,把以前的一些东西移植到这台机器上去,先远程看一下机器(其实就是一台虚拟机)配置,系统版本是Windows server2008R2 Enterprise,64位,4G内存,E7-885 ...

  10. 【原创】初识懒人开发库---ButterKnife

    今天再看别人代码的时候,看到了自己没见过的代码,看起来挺方便的,具体代码如下: @InjectView(R.id.iv_left) ImageView iv_left; @InjectView(R.i ...