本篇随笔与你们简单讨论一下在开发适配不一样分辨率、宽高比的Windows10 Universal App布局时的可行方式与小技巧。经验均从实践中总结,可能有诸多不完善和浅薄之处,欢迎读者严格指正。另外本文也只是抛砖引玉之用,但愿能收获更多更好的实战经验。css
说了这么多,咱们首先可能会问了,为何要作响应式设计?其缘由有如下两点:html
Windows10是微软宣称能够统一运行于PC&平板&手机&Xbox等诸多平台的操做系统,固然这也是universal一词的由来。若是你但愿你的应用不只仅局限于某一个平台,那么作一些响应式布局就很是必要了。前端
即便你的应用仅针对windows rt的平板用户,win10对于uwp的全新处理方式也让开发者不能免于分辨率适配。下图分别是Win8.1和Win10的应用商店应用对比:
不难发现,为了加强store app的实用度,桌面环境下的uwp是能够自定义窗口尺寸的。为了让应用别轻易被用户玩崩坏,整理整理仪容仍是至关有必要的。canvas
废话少说,接下来,咱们来看看手中能用于作响应式设计的手段吧。windows
不知道读者们有多少有html+css布局经历,这一套东西尽管在布局上不算完美,但用起来也算驾轻就熟,熟悉后能使网页布局有基本良好的适应性。
因此这里我就先说说网页前端布局与XAML布局的区别与联系吧。好消息是,一言以蔽之:几乎HTML能作的、XAML均可以。具体地说,几种在网页布局上常见手法xaml实现以下:app
也就是没有布局咯…对于结构简单的内容呈现(好比本篇博客),用这种方式足矣。如同下面的代码模型同样 框架
<!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>
有一种说法叫以不变应万变。
无论在什么状况下,这种布局方式是通配而广泛的:设计时固定页面尺寸,按照固定位置对每个元素进行布局,若是框架太小则使用滚动条浏览,框架过大则自动居中。反映在html中,则是无处不在的position:absolute。
这样的优势在于方便设计,能最大程度(或者说,丝绝不差)复现designer的设计,且节省工做量(如对于电脑设计一个1366x768的布局后通用所有窗口大小)。缺点则很明显:缺少灵活性,用户不友好,故只对于特定业务适用。 post
<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自身一些具备特点的属性/控件能进一步帮忙简化响应式布局,力求作到不用代码。
Viewbox是一个控件,会将其容纳的对象渲染成指定的宽高,在布局很难作出改变且须要适应的变化并不大时可使用该方法。
关于其具体使用的tips&tricks咱们会另起一篇日志介绍。
为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。
两者均为Windows10引入的新特性,前者用于容许其子元素按相对位置(附着下方、附着于上方、左右对齐等方式进行排版且在布局有变时自动调整保证其知足给定的位置关系);后者则定义多组VisualState,每个state对应页面上不一样控件的一些属性值,而在对应的state条件知足时自动将属性切换至目标值。此两点结合,将能够在不少状况下不用额外的C#代码实现响应布局。
关于此工具的具体用法,在以前发布的针对Build2015文章UWP?UWP! - Build 2015有些啥?(2)中已经说起,此处再也不赘述。
上面的方法都很差使?那就用code吧,麻烦是麻烦一点,其使用起来是最自由和可定制的,只要开发者心中有布局目标,就能知足一切排版需求。可是在用Code调整布局的过程当中,仍是有一些注意事项值得唠叨唠叨的:
显然,调整布局的code是事件驱动而不是一直运行的,那么写在什么事件里呢?首先你们应该能想到SizeChanged。是的,SizeChanged事件发生于对应目标的尺寸发生变化以后,也就是说,在该事件被触发时,保证能获取正确的宽高、从而根据获取到的数据进行动态布局,故将代码写进该事件是彻底正确的选择。须要注意的是,位置的变化(如canvas.left值改变)不会触发该事件。另外须要注意的一点是,在事件中写入的代码不能直接/间接修改自身相关的尺寸,不然引起雪崩效应,可能带来stackoverflow。
LayoutUpdated也能够用于尺寸变化检测,可是它是一个更广泛的事件:在布局树上的元素发生改变就会触发该事件,且该事件并不指定触发对象,若是跟踪该事件将发现不管窗口发生怎么样的改变,都将触发海量的LayoutUpdated事件。故将代码写于其中并不明智。
在根据尺寸动态布局的的代码中少不了获取ActualSize,但须要明确的是在布局刚作出改变时ActualSize是不会生效的,直接以该值做为基准势必致使错误。解决方案有2:1.如上文所言,将事件写于SizeChanged中,或将部分代码依赖该事件触发;2.强制调用UpdateLayout()方法,同步更新界面,从而能保证在该调用后得到的实际尺寸为真实尺寸。
布局方法千千万万,本文只从最小的几个地方入手简要介绍,若需作出真正用户友好、贴近业务需求的响应式布局,还需综合应用各类布局手段,了解各手段间优劣以及其最适合的应用场景,协同做用以创造好的布局。