博客园客户端(Universal App)开发随笔 -- 样式管理与夜间模式

以今天的眼光来看,一个好应用首先是要有好的用户体验。而好的用户体验最直观的就来自于用户界面。好的用户界面则需要好的设计,更需要好的实现。今天我们就向大家分享一下我们在使用Xaml实现界面设计上的一点心得。

样式管理

我们拿到的设计,大多是一张红线图,布满了距离,字号,色号,事无巨细的量化了我们的用户界面。如果我们就这样把各种属性照搬到上Xaml文件中,那看起来就非常不妙了,比如这样:

<TextBlock Text="首页"FontFamily =" Segoe WP "FontSize ="24"FontWeight =" Normal "TextTrimming =" CharacterEllipsis "TextWrapping =" Wrap "MaxLines ="2" Foreground="#FF297ACD " ></TextBlock>

一个看起来还好,但是通常我们的页面上不可能只有这一个控件。要是有上10个20个,那如果要修改其中一个属性可真是得看花了眼啊。

很幸运,我们在Universal应用的开发中可以把控件的相同属性归纳为资源(Resource),再在需要的时候应用到控件上就可以了。

有些很重要的单独的属性,以颜色为例,不同控件都会使用,却只有几个值,Universal应用可以把它单独抽象成一种 StaticResource 资源--Brush 。将它应用到控件的 Foreground 或者Background 之类的属性上时,就会像"brush(刷子)"一样把控件变为它的颜色。其中常用的SolidColorBrush 可以写成这样:

<SolidColorBrush x:Key=" PostTitleFont" Color="#FF297ACD"/>

将它放到资源字典或者页面的<Page.Resources> 中,就可以通过{StaticResource Brush的x:Key的值} 的形式来应用了。

而同一种控件的多个相同属性,我们可以把它们归纳成Style这种StaticResource资源,存在当前页面的 <Page.Resources> 中:

<Page.Resources>

<SolidColorBrush x:Key=" PostTitleFont" Color="#FF297ACD"/>

<Style x:Key="PostTitleFont" TargetType="TextBlock">

<Setter Property="FontFamily" Value="Segoe WP"/>

<Setter Property="FontSize" Value="24"/>

<Setter Property="FontWeight" Value="Normal"/>

<Setter Property="TextTrimming" Value="CharacterEllipsis"/>

<Setter Property="TextWrapping" Value="Wrap"/>

<Setter Property="MaxLines" Value="2"/>

<Setter Property="Foreground" Value="{StaticResourcePostTitleFont }"/>

</Style>

</Page.Resources>

Style 的 TargetType 属性指明了Style可以应用的元素,比如TargetType="TextBlock" 的Style是不能应用到Image 元素上的。而Style中包含的就是要应用的属性了,以 <Setter Property="属性名" Value="属性值"/> 这样的形式。

那么我们在当前页面的需要应用Sytle的地方,比如上面的情况,就只需要通过Style的x:Key 属性来应用:

<TextBlock Text="首页" Style="{StaticResource PivotTitleFont}"></TextBlock>

我们可以看到 Style="{StaticResource PivotTitleFont}" 中的 PivotTitleFont 就是 Style的 x:Key 属性,这样style就能够应用到 TextBlock 上了。

而且Style还能继承。比如我要一个 PostSubTitleFont, 只要字体比PostTitleFont 小一点。那我就可以这么写:

<Style x:Key="PostSubTitleFont" TargetType="TextBlock" BasedOn="{StaticResource PostTitleFont}">

<Setter Property="FontSize" Value="20"></Setter>

</Style>

这样一来如果我想改动它们的字体,只要在PostTitleFont中修改就可以了。是不是很方便?

当然我们通常也不止有一个页面,如果不想在每个页面中都把 Style 和 Brush 都贴一遍,就需要资源字典文件出场了。在我们的项目中添加一个资源字典文件:

再把我们的Style和 Brush都写在里面。然后在需要使用这些Style和 Brush的页面添加形如下面的代码把资源词典引用上就可以啦:

<Page.Resources>

<ResourceDictionary>

<ResourceDictionary.MergedDictionaries>

<ResourceDictionary Source="Dictionary.xaml" />

</ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

</Page.Resources>

当然,我们既然是Universal应用,能不能把Styl和 Brushe在Windows应用和Windows Phone应用间共享呢?答案是可以的。我们只要把资源文件放在.share项目下面,再在App.xaml中添加它的引用就可以:

<Application.Resources>

<ResourceDictionary>

<ResourceDictionary.MergedDictionaries>

<ResourceDictionary Source="Dictionary.xaml" />

</ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

</Application.Resources>

这样Dictionary.xaml中的Style和 Brush就在Windows应用和Windows Phone应用的所有页面都有效了。

等等,那Windows应用和Windows Phone应用间有所区别的Style和 Brush怎么办呢?

也有办法。只要在Windows项目和Windows Phone项目中各添加一个同名的资源词典文件比如DifferentDictionary.xaml,把不同的Style和 Brush写入,再在App.xaml中引用就能够实现了。

<Application.Resources>

<ResourceDictionary>

<ResourceDictionary.MergedDictionaries>

<ResourceDictionary Source="Dictionary.xaml" />

<ResourceDictionary Source="DifferentDictionary.xaml" />

</ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

</Application.Resources>

这样,我们通过Resource 和资源词典文件大大简化了用户界面设计的实现过程,是不是很方便呢?

夜间模式

说到阅读软件的用户体验,就不得不提到夜间模式了。下面就说说我们在Windows Phone应用上实现夜间模式的过程吧。

大家可能都在Windows Phone 设置的 开始屏幕+主题 中设置过背景和主题色,当我们修改了背景的 黑/白 后,几乎所有的系统应用的背景色和文字的颜色都立刻改变了,连重启应用都不用。

我们实现的夜间模式正是利用了这个功能。

在Windows Phone应用中,如果我们设置了当前 Page的 RequestedTheme 属性为Light 或者Dark的话就相当于我们在系统设置里修改了背景黑/白。比如通常情况下我们新建一个应用,默认的情况下都是黑底白字:

而如果我们把Page的 RequestedTheme 属性设为的话,可以看到在设计视图中应用变成了白底黑字:

那么我们通过settings页面的一个 ToggleSwitch控件实时切换RequestedTheme这一属性,就可以实时控制应用的各种颜色如背景色,文字颜色为Light或Dark对应的颜色。我们把Light设为日间模式,Dark设为夜间模式。简单一点的情况下可以把 ToggleSwitch 的Toggled事件响应方法设为如下:

private void ts_LightMode_Toggled(object sender, RoutedEventArgs e)

{

if (this.RequestedTheme == ElementTheme.Light)

{

this.RequestedTheme = ElementTheme.Dark;

}

else

{

this.RequestedTheme = ElementTheme.Light;

}

}

接下来如何设置日间模式/夜间模式对应的颜色呢?

在之前的样式管理一节中我们提到了通过{StaticResource PivotTitleFont } 的形式来应用 SolidColorBrush 资源,但是我们在资源 PostTitleFont 定义的时候只写了一个值,系统会自动帮我们转换么?事实上并没有那么简单。我们需要通过 ThemeResource 类型的资源预先设置好2种模式对应的颜色。应用了这种 ThemeResource 资源以后,这个控件就能够响应 RequestedTheme 属性的变化,即时切换显示对应模式的颜色。

那么怎样加入这种资源呢?我们可以打开我们的资源字典 Dictionary.xaml ,在里面加入这样一段代码:

<ResourceDictionary.ThemeDictionaries>

<ResourceDictionary x:Key="Light">

</ResourceDictionary>

 

<ResourceDictionary x:Key="Dark">

</ResourceDictionary>

</ResourceDictionary.ThemeDictionaries>

这里 x:Key 分别为Dark/ Light 的 ResourceDictionary 中,就是我们存放对应两种模式的资源的地方。比如我们希望页面背景在日间模式下是 蓝色,夜间模式下是深灰色,就可以这么写:

<ResourceDictionary.ThemeDictionaries>

<ResourceDictionary x:Key="Light">

<SolidColorBrush x:Key="myPageBackground" Color="Blue"></SolidColorBrush>

</ResourceDictionary>

 

<ResourceDictionary x:Key="Dark">

<SolidColorBrush x:Key="myPageBackground" Color="DarkGray"></SolidColorBrush>

</ResourceDictionary>

</ResourceDictionary.ThemeDictionaries>

在我们的page中就可以这样应用 ThemeResource 资源了:

<Page

x:Class="my_universal.CnblogsMainPage"

xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="using:my_universal"

xmlns:d="https://schemas.microsoft.com/expression/blend/2008"

xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"

mc:Ignorable="d"

RequestedTheme="Light"

Background="{ThemeResourcemyPageBackground }">

是不是一点都不难呢?

另外我们还发现有两点值得注意:

一是我们可以覆盖系统的 ThemeResource 。我们可以选中任意一个 TextBlock 控件,打开属性栏,选择 Foreground 属性的画笔资源。

可以看到下方以ThemeBrush结尾的都是系统的 ThemeResource 资源,只要在我们的 x:Key 分别为Dark/ Light 的 ResourceDictionary 里加入和它们同名的资源,就能够覆盖它们了。

二是对于Flyout 类型的控件,应用到它上面的 ThemeResource 资源是相反的。就是说当RequestedTheme 属性为 Light 时,Flyout 类型的控件会应用 Dark ResourceDictionary 中的资源。反之亦然。

小结

今天就先向大家分享这些心得,欢迎大家继续关注和拍砖,让我们共同进步。

 

我们的已经发布的应用和代码可以在下面找到:

 

Windows Phone Store App link:

https://www.windowsphone.com/zh-cn/store/app/博客园-uap/500f08f0-5be8-4723-aff9-a397beee52fc

 

Windows Store App link:

https://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059

 

GitHub open source link:

https://github.com/MS-UAP/cnblogs-UAP

 

MSDN Sample Code:

https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab