Viewbox在UWP开发中的应用
Windows 8.1 与Windows Phone 8.1的UAP应用,终于在Windows 10上统一到了UWP之下。原来3个不同的project也变为一个。没有了2套xaml页面,我们需要用同一个页面适应所有的设备。更麻烦的是在Desktop设备上,我们的应用窗口是可以随意拖动大小的。这对我们的UI布局提出了更高的要求。当然我们也有了新的工具来应对:
VisualState中增加了StateTriggers,通过不同的条件触发Trigger并自动切换到对应的VisualState,还能加入自己定义触发条件的Trigger。
新增了RelativePanel控件,可以让其中的元素使用相对位置布局来适应不同的设备和窗口大小。
另一方面微软官方也发布了一些指导建议,比如Responsive design 101 for Universal Windows Platform (UWP) apps , UI basics for Universal Windows Platform (UWP) apps, Plan your Universal Windows Platform (UWP) app 等一系列文章。这对我们也很有启发。
然而这些都没有具体提到对于窗口大小拖动情况下的处理,下面就来分享一下我们在尝试开发UWP应用的过程中对这种情况的一些思考。
总体布局
我们的应用,总体上是非常简单地采用了UI basics for Universal Windows Platform (UWP) apps 中 图1和图2 的布局,有着始终显示的顶栏和底栏,中间则是内容显示区域。

如果沿用UAP的设计,我们可能会为顶栏和底栏设计一个固定高度,让中间的内容区域可以随屏幕大小来变化。然而在UWP中,我们的应用窗口可以在最小500 X 320,到全屏之间自由变化。如果仍然采用固定高度,那在窗口变小的情况下,内容区域就会被顶栏和底栏挤压,这并不是我们希望的。所以我们在全局的布局上采用了按比例分配的策略:
<Grid.RowDefinitions>
<RowDefinition x:Name="rd_1" Height="*" ></RowDefinition>
<RowDefinition x:Name="rd_2" Height="8*"></RowDefinition>
<RowDefinition Height="60*"></RowDefinition>
<RowDefinition x:Name="rd_4" Height="8*" ></RowDefinition>
<RowDefinition x:Name="rd_5" Height="*" ></RowDefinition>
</Grid.RowDefinitions>
这样一来在不同的窗口大小和设备的情况下都可以有所兼顾。
但这又带来新的问题:我们顶栏和底栏中的文字,图片大多是固定大小的。怎样才能让它们随屏幕和设备自动适应呢?用新的StateTriggers固然可以,但对于每个固定大小的控件,都要指定它们在不同VisualState下的新大小,有些麻烦。而且我们的布局并没有很大的变化,没有一定使用StateTriggers必要。所以这里我们想到了Viewbox 控件。Viewbox 是一个可以将其中内容缩放到自身大小的容器。我们在按比例划分的Grid中放入Viewbox ,再把顶栏和底栏放到Viewbox 中,这样他们就可以在不同窗口大小和设备上都保持统一的比例了:
<Viewbox x:Name="vbNav" Grid.Row="1" HorizontalAlignment="Left" Visibility="Visible">
<Grid Margin="50,0" >
<Image Source="{StaticResource mainPageMenuLeftImg}" Stretch="Uniform" HorizontalAlignment="Left" Height="160"
Margin="-20,0,0,0" VerticalAlignment="Center" Canvas.ZIndex="100"></Image>
<ListView x:Name="lvNav" SelectionMode="Single" Height="160" Canvas.ZIndex="99"
SelectionChanged="lvNav_SelectionChanged" HorizontalAlignment="Left"
VerticalAlignment="Center" ScrollViewer.HorizontalScrollMode="Enabled"
Background="#FFF6EBA1" ItemContainerStyle="{StaticResource ContextControlItemContainerStyle}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" Margin="0" VerticalAlignment="Center"></VirtualizingStackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<Image Source="{StaticResource mainPageMenuRightImg}" Stretch="Uniform" HorizontalAlignment="Right" Height="160"
Margin="0,0,-20,0" VerticalAlignment="Center" Canvas.ZIndex="100"></Image>
</Grid>
</Viewbox>
这里的image和listview都是固定大小的,使用了viewbox以后就可以始终保持只占屏幕一定比例,而不会在小屏幕上超出Grid而在大屏幕上显得比较小了。
内容布局
我们的页面内容有2种,一种是内容列表,一种则是包括编辑和预览的界面。
对于内容列表,我们使用了Responsive design 101 for Universal Windows Platform (UWP) apps中的resize策略。
主要是一个横向滚动的GridView,在屏幕足够高的情况下显示3行或4行内容,较小的情况下则显示2行。然而这个较小的情况实际上覆盖了比较大的范围,如果仍然使用固定大小的列表元素控件则会遇到和顶栏和底栏类似的问题。所以我们又一次使用了viewbox: 将内容区域放一个Grid在最外层,再把包含GridView的viewbox放在其中。响应最外层的Grid的sizechange事件,改变GridView的长宽比例以适应显示区域。
Xaml:
<Grid x:Name="grid_content" SizeChanged="gridRoot_SizeChanged" Grid.Row="2">
<Viewbox>
<GridView x:Name="gv_Content" ItemContainerStyle="{StaticResource contentTemplateStyle}"
SelectionMode="Single" IsSynchronizedWithCurrentItem="{x:Null}"
SelectionChanged="gvContent_SelectionChanged" IsItemClickEnabled="True"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Width="630"
Height="774"
ScrollViewer.HorizontalScrollMode="Enabled" ScrollViewer.HorizontalScrollBarVisibility="Visible"
Margin="20">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Vertical" Margin="0" MaximumRowsOrColumns="4" VerticalAlignment="Top"></WrapGrid>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</Viewbox>
</Grid>
CS:
private void gridRoot_SizeChanged(object sender, SizeChangedEventArgs e)
{
try
{
Grid thisGrid = sender as Grid;
if (thisGrid.ActualHeight >=480 && thisGrid.ActualHeight <=720)
{
this.gv_Content.Height = 784 * 1.5; //改变高度,放3个列表元素
}
else if (thisGrid.ActualHeight >720)
{
this.gv_Content.Height = 784 * 2; //改变高度,放4个列表元素
}
else
{
this. gv_Content.Height = 784; //改变高度,放2个列表元素
}
this. gv_Content.Width = thisGrid.ActualWidth / (thisGrid.ActualHeight) * this. gv_Content.Height; //调整宽度,适应显示区域比例
}
catch (Exception ex)
{
Debug.WriteLine(ex.Source + "\r\n" + ex.Message + "\r\n" + ex.StackTrace);
}
}
而包含编辑和预览的界面,我们则采取了在屏幕宽度较小的时候将预览界面隐藏,让界面可以在编辑和预览之间切换的策略。
小结
以上就是我们面对UWP在UI布局方面新特性的一部分心得,希望能抛砖引玉,吸引更多的小伙伴加入到UWP的开发中来。
Viewbox在UWP开发中的应用的更多相关文章
- UWP开发中的方向传感器
在UWP开发中,我们能使用的到方向有三种: OrientationSensor下的四元数:Compass罗盘的HeadingMagneticNorth:以及SimpleOrientationSenso ...
- Windows10(uwp)开发中的侧滑
还是在持续的开发一款Windows10的应用中,除了上篇博客讲讲我在Windows10(uwp)开发中遇到的一些坑,其实还有很多不完善的地方,比如(UIElement.Foreground).(Gra ...
- Win10 UWP开发中的重复性静态UI绘制小技巧 2
小技巧1 地址:http://www.cnblogs.com/ms-uap/p/4641419.html 介绍 我们在上一篇博文中展示了通过Shape.Stroke族属性实现静态重复性UI绘制,使得U ...
- 讲讲我在Windows10(uwp)开发中遇到的一些坑.
7月29日发布的Windows10正式版,当天安装好以后,在网络不太好的情况下,经过多次尝试终于装上了Visual Studio 2015和Windows 10 10240的SDK.这两周一直在开发U ...
- Win10 UWP开发中的重复性静态UI绘制小技巧 1
介绍 在Windows 10 UWP界面实现的过程中,有时会遇到一些重复性的.静态的界面设计.比如:画许多等距的线条,画一圈时钟型的刻度线,同特别的策略排布元素,等等. 读者可能觉得这些需求十分简单, ...
- UWP开发中两种网络图片缓存方法
通常情况下,我们的程序需要从服务器读取图片,但如果需要不止一次读取某一张图片的话,就需要做本地缓存了,这样既为用户省一点流量,又能显得你的APP很快. 假如你已经知道了某一张图片的地址,那么第一件事就 ...
- 随记:UWP开发中怎么使当前页面拓展到标题栏
public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); CoreAp ...
- UWP开发中的流媒体
写这篇的目的只是为了记住这个东西, win10原生支持HLS了 AdaptiveMediaSourceCreationResult amsResult = await AdaptiveMediaSou ...
- 领域驱动和MVVM应用于UWP开发的一些思考
领域驱动和MVVM应用于UWP开发的一些思考 0x00 起因 有段时间没写博客了,其实最近本来是根据梳理的MSDN上的资料(UWP开发目录整理)有条不紊的进行UWP学习的.学习中有了心得体会或遇到了问 ...
随机推荐
- poj3009
#include <stdio.h> int H,L; int qx,qy,zx,zy; int map[21][21]; int ax[4]={-1,0,1,0}; int ay[4]= ...
- [game]十字链表的AOI算法实现
AOI主要有九宫格.灯塔和十字链表的算法实现.本文阐述十字链表的实现和尝试. 1. 基本原理 根据二维地图,将其分成x轴和y轴两个链表.如果是三维地图,则还需要维护多一个z轴的链表.将对象的坐标值按照 ...
- mysql解压缩安装(一)
MySQL安装文件分为两种,一种是msi格式的,一种是zip格式的.如果是msi格式的可以直接点击安装,按照它给出的安装提示进行安装(相信大家的英文可以看懂英文提示),一般MySQL将会安装在C:\P ...
- hdoj 1272 小希的迷宫
上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了 ...
- app.js
//第一步,引入express模块 var exp = require('express'), http = require('http'),//引入http模块 path = req ...
- C# onverride、abstract、vitrtual、new、sealed
abstract: 抽象方法是隐式的虚方法 在抽象方法声明中,不能使用static或者virtual修饰符 override: override关键字提供派生类对基类方法的新的实现,重写的基类方法必须 ...
- 开启Python之路
开始自学Python 环境配置 自己百度去!!! 计算与变量 字符创.列表.元组和字典 简单的画图 使用if和else条件控制语句 循环 使用函数和模块来重用代码 使用类和对象 Python内建函数的 ...
- Spring学习笔记 5. 尚硅谷_佟刚_Spring_自动装配
1,回顾以前的做法 一个人有姓名,有住址,有一辆车.其中住址和车也是一个类,这种情况下不用自动装配是十分容易实现的 (1)Person类 package com.zsq; public class P ...
- [转]JUnit-4.11使用报java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing错误
原文引自: http://blog.csdn.net/castle07/article/details/8553704 今天尝试使用JUnit,下载了最新的JUnit版本,是4.11,结果尝试使用发现 ...
- 从up6-down2升级到down3
概述: 添加存储过程down_f_process.sql,down_f_del.sql 更新DnFile.updateProcess,DnFile.Delete 更新down.js 更新down.fo ...