响应式布局的概念是一个页面适配多个终端及不同分辨率. 在针对特定屏幕宽度优化应用 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
是 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 包 https://www.nuget.org/packages/Microsoft.UI.Xaml/ ):
- <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
来源: https://www.cnblogs.com/dino623/p/responsive-layouts-with-xaml.html