[UWP]XAML中的响应式布局技术
响应式布局的概念是一个页面适配多个终端及不同分辨率。在针对特定屏幕宽度优化应用 UI 时,我们将此称为创建响应式设计。WPF设计之初响应式设计的概念并不流行,那时候大部分网页设计师都按着宽度960像素的标准设计。到了UWP诞生的时候响应式布局已经很流行了,所以UWP提供了很多响应式布局的技术,这篇文章简单总结了一些响应式布局常用的技术,更完整的内容请看文章最后给出的参考网站。
1. 传统的XAML如何适配不同分辨率
所谓的传统,是指在响应式设计没流行前XAML就已经存在的应对不同分辨率的技术,毕竟桌面客户端常常也调整窗体的大小,有些人还同时使用两个不同分辨率的屏幕。以我的经验来说以下这些做法可以使UI有效应对分辨率改变:
- 使用相对定位代替决定定位
- 使用
*
和Auto
代替具体尺寸(除了间距) - 使用WrapPanel代替StackPanel
- 不要忘记使用ScrollViewer
不同的DPI设定、不同的本地化字符串长度都可能使整个页面布局乱掉。而且和网页不同,WPF窗体默认没有提供ScrollViewer,所以千万不能忘记。在桌面客户端合理使用以上技术可以避免客户投诉。但UWP主打跨平台,它需要更先进(或者说,更激进)的技术。
2. 响应式设计技术
微软的官方文档介绍了UWP中响应式设计常用的6个技术,包括重新定位、调整大小、重新排列、显示/隐藏、替换和重新构建,具体可见以下网站:
响应式设计技术 - UWP apps Microsoft Docs
3. AdaptiveTrigger
AdaptiveTrigger是UWP中一种最常用的响应式布局技术。VisualStateManager用于管理UI的视觉状态,可以在UI上设置多个视觉状态,然后用VisualStateManager.GoToState
在这些状态间切换,了解自定义控件的开发者对这点应该都不陌生。UWP提供了AdaptiveTrigger
这个状态触发器,它以MinWindowWidth
和MinWindowHeight
未条件,根据页面宽度或高度进入设定好的不同状态(通常来说只使用MinWindowWidth
,同时使用Height和Width做条件很容易产生混乱,而且大部分情况下响应式布局都会使用垂直滚动条所以对高度不关心。)在下面的示例中StackPanel默认使用垂直排列,当页面的宽度超过720像素时改为水平排列。
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<!--VisualState to be triggered when window width is >=720 effective pixels.-->
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="myPanel.Orientation"
Value="Horizontal" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<StackPanel x:Name="myPanel"
Orientation="Vertical">
<TextBlock Text="This is a block of text. It is text block 1. "
Style="{ThemeResource BodyTextBlockStyle}" />
<TextBlock Text="This is a block of text. It is text block 2. "
Style="{ThemeResource BodyTextBlockStyle}" />
<TextBlock Text="This is a block of text. It is text block 3. "
Style="{ThemeResource BodyTextBlockStyle}" />
</StackPanel>
</Grid>
使用AdaptiveTrigger可以做到前一节中提到的UWP中响应式设计常用的6个技术,除了UWP自带的AdaptiveTrigger,也可以自定义StateTriggerBase
,这将在下一篇文章中介绍。
4. NavigationView
UWP中部分控件已经实现了响应式行为, 最典型的就是NavigationView。可以使用 PaneDisplayMode 属性配置不同的导航样式或显示模式。默认情况下,PaneDisplayMode 设置为 Auto。在 Auto 模式下,导航视图会进行自适应,在窗口狭窄时为 LeftMinimal,接下来为 LeftCompact,随后在窗口变宽时为 Left。
XAML Controls Gallery就是一个很好的结合NavigationView
的响应式布局示例:
5. 定制布局
如果AdaptiveTrigger
需要设置的属性太多,倒不如直接切换UI,最简单的做法是整个显示/隐藏,例如这样:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState>
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="720" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="NormalView.Visibility"
Value="Collapsed" />
<Setter Target="LargelView.Visibility"
Value="Visible" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid x:Name="NormalView">
<!--some xmal-->
</Grid>
<Grid x:Name="LargelView"
Visibility="Collapsed">
<!--some xmal-->
</Grid>
</Grid>
这种时候MVVM的优势就体现出来了,因为VIEW和VIEWMODEL解耦了,VIEW随便换,而且整个UI显示隐藏说不定比多个小模块独自改变性能更好。说到性能,UWP的很多场景都为已经死了多年的WindowsWobile考虑了性能,更不用说现在的桌面平台,所以做UWP不需要太过介意性能,尤其是已经在WPF上培养出小心翼翼的习惯的开发者,UWP的性能问题等真的出现了再说。
除了使用显示隐藏,UWP还可以使用限定符名称指定CodeBehind对应的XAML文件,这有点像是自适应应用的话题。使用格式如下:
[pageName] .DeviceFamily- [qualifierString] .xaml
如果要用在文件夹,格式如下:
DeviceFamily- [qualifierString]
要更灵活些,可以根据条件跳转到不同的页面:
if (Windows.System.Profile.AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Tablet")
{
rootFrame.Navigate(typeof(MainPage_Tablet), e.Arguments);
}
else
{
rootFrame.Navigate(typeof(MainPage), e.Arguments);
}
虽然示例代码这样写,其实现在除了桌面几乎没有其它平台了,所以大部分情况下还是根据当前尺寸跳转。
6. compact size
正如前面所说,既然已经不需要其它平台,那UWP的响应式布局大部分情况都是为了应对尺寸问题,Windows UI Library还提供了一个紧凑的主题用于小尺寸UI(需要安装Microsoft.UI.Xaml的Nuget包):
<Page.Resources>
<ResourceDictionary Source="ms-appx:///Microsoft.UI.Xaml/DensityStyles/Compact.xaml" />
</Page.Resources>
private void Standard_Checked(object sender, RoutedEventArgs e)
{
ContentFrame.Navigate(typeof(SampleStandardSizingPage), null, new SuppressNavigationTransitionInfo());
}
private void Compact_Checked(object sender, RoutedEventArgs e)
{
ContentFrame.Navigate(typeof(SampleCompactSizingPage), null, new SuppressNavigationTransitionInfo());
}
7. ViewBox
ViewBox可以根据自身大小放大或缩小它的Content元素,某些情况下它是WPF和UWP平台的终极响应式设计解决方案,因为WPF/UWP元素都是矢量元素所以大部分元素都可以无损缩放(当然会有像素对不齐的情况),所以偷懒的话就可以使用ViewBox:
8. 参考
采用 XAML 的响应式布局 - UWP apps Microsoft Docs
响应式设计技术 - UWP apps Microsoft Docs
响应式设计的屏幕大小和断点 - UWP apps Microsoft Docs
导航视图 - UWP apps Microsoft Docs
AdaptiveTrigger Class (Windows.UI.Xaml) - Windows UWP applications Microsoft Docs
[UWP]XAML中的响应式布局技术的更多相关文章
- Css3中的响应式布局的应用
Media Queries直译过来就是“媒体查询”,在我们平时的Web页面中head部分常看到这样的一段代码: <link href="css/reset.css" rel= ...
- Bootstrap禁用响应式布局
在Bootstrap中极其重要的一个技术内容便是响应式布局了,一次编码针对不同设备终端的强大能力使得响应式技术愈发流行. 不过正所谓"萝卜青菜各有所爱",如果你想要使用Bootst ...
- HTML5 respond.js 解决IE6~8的响应式布局问题
HTML5 respond.js 解决IE6~8的响应式布局问题 响 应式布局,理想状态是,对PC/移动各种终端进行响应.媒体查询的支持程度是IE9+以及其他现代的浏览器,但是IE8在市场当中仍然 ...
- 响应式布局中的CSS相对量
一个响应式布局,要能够根据设备屏幕尺寸的改变,动态的调整页面内容,展现不同的设计风格. 在进行响应式的 CSS 代码编写过程中,经常会用到一些相对尺寸,以达到相对定位的目的.例如,常见的响应式布局中需 ...
- 响应式布局中为什么要使用em设置字体大小而不用px
px像素(Pixel).相对长度单位.像素px是相对于不同设备显示器屏幕分辨率(pad/phone/pc)而言的.(引自CSS2.0手册) 1em指的是一个字体的大小,它会继承父级元素的字体大小,因此 ...
- NopCommerce 3.4中移动端访问抛弃响应式布局
在Nop3.4中,他抛弃了原来的xxx.Mobile.cshtml的这种写法,而是采用了响应式布局,并且把规则也给改了,你在后台配置不启用响应式布局,在前台你仍然不能写xxx.Mobile.cshtm ...
- 响应式布局中重要的meta标签设置.适用于手机浏览器兼容性设置
<!-- #手机浏览器兼容性设置 --> <meta content="application/xhtml+xml;charset=UTF-8" http- ...
- 分享大麦UWP版本开发历程-01.响应式轮播顶部焦点图
话说有一天,临近下班无心工作,在网上看各种文章,阅读到了一篇名为<聊聊大麦网UWP版的首页顶部图片联动效果的实现方法>(传递:http://www.cnblogs.com/hippieZh ...
- 一步步开发自己的博客 .NET版 剧终篇(6、响应式布局 和 自定义样式)
前言 这次开发的博客主要功能或特点: 第一:可以兼容各终端,特别是手机端. 第二:到时会用到大量html5,炫啊. 第三:导入博客园的精华文章,并做分类.(不要封我) 第四:做 ...
随机推荐
- 字母间距letter-spacing
效果图: 字母间距CSS: h1 {letter-spacing:2px} h2 {letter-spacing:-3px}
- ipykernel_launcher.py: error: unrecognized arguments: -f /Users/apple/Library/Jupyter/runtime/kernel
当在jupyter下使用parser.parse_args()出错则改换为parser.parse_known_args()[0]其效用是差不多的,至于为什么出现错误,我也不知道…
- pytorch之expand,gather,squeeze,sum,contiguous,softmax,max,argmax
目录 gather squeeze expand sum contiguous softmax max argmax gather torch.gather(input,dim,index,out=N ...
- 零基础入门--中文命名实体识别(BiLSTM+CRF模型,含代码)
自己也是一个初学者,主要是总结一下最近的学习,大佬见笑. 中文分词说到命名实体抽取,先要了解一下基于字标注的中文分词.比如一句话 "我爱北京天安门”. 分词的结果可以是 “我/爱/北京/天安 ...
- 2019-9-2-本文说如何显示SVG
title author date CreateTime categories 本文说如何显示SVG lindexi 2019-09-02 12:57:38 +0800 2018-2-13 17:23 ...
- Python--day41--递归锁Rlock
1,递归锁Rlock:递归锁是为了解决死锁问题,且递归锁的特点是在同一个线程中可以被acquire()多次 多个acquire()在递归锁中不会阻塞,而互斥锁Lock就会阻塞 代码示例: from t ...
- spring boot The request was rejected because the URL was not normalized
升级spring boot 1.5.10.RELEASE 版本后,突然发现之前能Nginx代理能请求的地址抛如下异常: org.springframework.security.web.firewal ...
- [转]在ASP.NET WebAPI 中使用缓存【Redis】
初步看了下CacheCow与OutputCache,感觉还是CacheOutput比较符合自己的要求,使用也很简单 PM>Install-Package Strathweb.CacheOutpu ...
- 解决:javac: 无效的目标发行版: 1.8
原 解决:javac: 无效的目标发行版: 1.8 2017年06月14日 16:21:12 代码也文艺 阅读数 44795 版权声明:本文为博主原创文章,未经博主允许不得转载. https://bl ...
- 【hdu 1112】The Proper Key
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s) ...