博客园客户端(Universal App)开发随笔 - Setting Page的实现方法与经验

前言

几乎所有的移动 App 都会为用户提供一个设置页面(Setting Page 或 Preference Page),来满足大家对于一个 App 众口难调的需求。虽然有一种说法表示,最好的 App 不需要设置,一切默认呈现给用户的就是最好的选择。但是对于大多数开发人员来说,这样的境界不是可以简单达到的;而且对于部分“设置控”用户来说,没有设置页面怎么看都觉得少了些什么。所以对于大部分 App 来说,设置页面还是一个必备品。

本文将分别介绍 Windows 和 Windows Phone 的设置页面的界面设计,最后介绍他们后台的统一实现与数据保存。

 

Windows App 的Setting界面设计

在 Windows App 中,设置页面的入口被统一在了 charm bar 中,手指从触摸屏右侧滑入或鼠标从屏幕右下角向下滑动都可以调出 charm bar,然后进入默认的设置页面。

screenshot_12112014_164857

开发中的默认的设置页面只有 Permissions (权限)一项,发布在市场后会自动添加 Rate and Review (评分)这一项,所以不必自己实现,但是在Windows Phone中需要自己实现。

screenshot_12112014_165037

对于一个一般的 App 来说,可以在设置页面添加如下几项:

  • 选项 / 偏好 (Option / Preference)
  • 关于(About)
  • 隐私声明(Privacy Statement)(如果 App 使用了网络权限,则这一项必选)

 

选项 / 偏好 (Option / Preference)

以博客园应用下一版即将加入的阅读模式为例。我们希望在选项中新增阅读模式的设置,具体实现方式为在 App 的设置中增加选项一栏,点击后跳转到选项页面,并进行相应设置。

首先我们在 Universal App 中添加一个 Setting Flyout 页面:

1

在XAML部分,我们加入简单的说明与一个 ToggleButton。

复制代码

 <StackPanel Style="{StaticResource SettingsFlyoutSectionStyle}">
            <TextBlock Text="阅读设置" Style="{StaticResource TitleTextBlockStyle}"/>
            <TextBlock Margin="0,0,0,10" Text="在阅读设置部分,可以进行所有和阅读相关的设置" Style="{StaticResource BodyTextBlockStyle}"/>
            <ToggleSwitch Margin="-6,0,0,0" x:Name="ReadingModeToggle" Header = "阅读模式" HorizontalAlignment="Left" HorizontalContentAlignment="Left" OffContent="日间模式" OnContent="夜间模式" Toggled="ReadingModeToggle_Toggled"/>
        </StackPanel>

复制代码

这样就实现了一个最简单的 SettingFlyout 页面。那么如何在 App 中调出这个页面呢?我们在App.xaml.cs文件中添加如下代码:

 #if WINDOWS_APP
using Windows.UI.ApplicationSettings;
#endif

并在 OnLaunched 方法内添加:

复制代码

 #if WINDOWS_APP
            SettingsPane.GetForCurrentView().CommandsRequested += (s, args) =>
            {
                Add an About command to the settings pane
                var preference = new SettingsCommand("设置", "设置", (handler) =>
                new PreferenceSettingsFlyout().Show());
                args.Request.ApplicationCommands.Add(preference);
            };
#endif

复制代码

这样,打开应用时,在右侧的 Setting Pane 中就增加了我们的选项一栏,并可以打开进行设置。

screenshot_12112014_165338screenshot_12112014_165344

具体设置的后台实现,可以通过 Toggled="ReadingModeToggle_Toggled" 调用后台的具体方法实现。这一部分的有关内容将在后文提到。

关于(About)

关于(About)页面可以放置 App 相关的介绍与作者联系方式等信息,具体的实现与选项 / 偏好 (Option / Preference) 页面相似,此处不再赘述。

隐私声明(Privacy Statement)

这一项比较特殊,凡是申请了网络权限,包括 internetClient,internetClientServer 和 privateNetworkClientServer 权限的 App,都必须提供隐私声明。开发者可以在自己的网站或博客建立一个专门的页面用来放置应用的隐私声明,并在设置栏中提供一个转向的入口,这样才能确保 App 在提交时通过审核。

由于只需要跳转的链接,所以隐私声明的实现比较简单。首先在 App.xaml.cs 的 OnLaunched 方法内添加:

 #if WINDOWS_APP
                var privacy = new SettingsCommand("隐私声明", "隐私声明", GetPrivacyPolicyAsync);
                args.Request.ApplicationCommands.Add(privacy);
#endif

提供隐私声明的入口,并在 App.xaml.cs 中添加以下方法:

复制代码

 #if WINDOWS_APP
        private async void GetPrivacyPolicyAsync(Windows.UI.Popups.IUICommand command)
        {
            await Windows.System.Launcher.LaunchUriAsync(new Uri("https://www.microsoft.com/privacystatement/zh-cn/core/default.aspx"));
        }
#endif

复制代码

即可以实现。其中的 URL 请替换为适合 App 本身的隐私声明地址。

 

Windows Phone App的Setting界面设计

Windows Phone App 与 Windows App 在设置界面方面有两点不同:

1. Windows Phone 没有提供统一的设置入口。

2. Windows Phone App 不需要强制提供隐私声明。

因此,开发者需要自己为设置界面提供入口和界面页面。以博客园 UAP 的 Windows Phone 版举例,首先我们在项目中添加 SettingPage.xaml。

2

博客园的设置页面实现使用了 Pivot,好处是可以在一个页面同时实现“选项”与“关于”两项内容,并且将来可以很方便地添加新的子项。

复制代码

 <Pivot x:Name="pivot_Main" SelectionChanged="Pivot_SelectionChanged">
        <PivotItem Margin="0" Tag="setting">
            <PivotItem.Header>
                <TextBlock Style="{StaticResource PivotTitleFont}" Text="设置" />
            </PivotItem.Header>
            <StackPanel Orientation="Vertical" Margin="20">
                <ToggleSwitch Header="博客标题/摘要" OffContent="只显示标题" OnContent="显示标题和摘要" IsOn="{Binding DefaultDisplaySummary, Mode=TwoWay}"/>
                    <TextBlock Text="(刷新生效)" Foreground="{ThemeResource CNBlogsAttributionColor}" FontSize="14" Margin="0,-5,0,10"/>
                <ToggleSwitch Header="点击博客标题时" OffContent="阅读正文" OnContent="显示/隐藏摘要" IsOn="{Binding ClickTitleForSummary, Mode=TwoWay}"/>
                    <TextBlock Text="(刷新生效)" Foreground="{ThemeResource CNBlogsAttributionColor}" FontSize="14" Margin="0,-5,0,10"/>
            </StackPanel>
        </PivotItem>

        <PivotItem Margin="0" Tag="about">
            <PivotItem.Header>
                <TextBlock Style="{StaticResource PivotTitleFont}" Text="关于" />
            </PivotItem.Header>
            <StackPanel Margin="20" HorizontalAlignment="Center">
                    <Image x:Name="image_Logo" Height="100" Margin="0,20" Source="ms-appx:///Assets/Logo.100.Blue.png" Opacity="0">
                    <Image.Projection>
                        <PlaneProjection />
                    </Image.Projection>
                </Image>
                <StackPanel x:Name="sp_aboutContent" Opacity="0">
                        <TextBlock Margin="0,10" HorizontalAlignment="Center" Style="{StaticResource SettingPageTextHeader}" Text="博客园" />
                        <TextBlock Margin="0,10" HorizontalAlignment="Center" Style="{StaticResource SettingPageTextHeader}" Text="Windows Phone 客户端" />
                    <TextBlock HorizontalAlignment="Center" FontSize="14" Style="{StaticResource SettingPageTextHeader}" Text="Powered By Microsoft" />
                    <TextBlock x:Name="tbkVersion" Text="1.0" HorizontalAlignment="Center" FontSize="14" Style="{StaticResource SettingPageTextHeader}"/>
                    <HyperlinkButton x:Name="btn_RateMe" Margin="0,40,0,10" Content="给个好评" Style="{StaticResource SettingPageHyperlinkButtonText}" HorizontalAlignment="Center" Click="btn_RateMe_Click"/>

                        <TextBlock Margin="30" FontSize="14" FontFamily="Segoe WP" TextWrapping="Wrap" Foreground="{ThemeResource CNBlogsSummaryColor}">
                        <Run Text="本应用为Universal App的示例应用,使用WindowsRT SDK开发,支持Windows Phone 8.1。"/>
                        <Run Text="还有一个同名应用同时发布在Windows 8.1上,两者共用一套底层代码。"/>
                    </TextBlock>
                </StackPanel>
            </StackPanel>
        </PivotItem>
    </Pivot>

复制代码

通过以上代码框架实现设置和关于页面的内容填充,即可实现简单的设置页面效果。

34

在“关于”页面中的那个“给个好评”,必须自己实现,两行代码搞定:

?

1 2 var uri = new Uri(string.Format("ms-windows-store:navigate?appid={0}", urrentApp.AppId)); await Windows.System.Launcher.LaunchUriAsync(uri);

 上面的那个版本号,也可以用code从Package.appxmanifest中的这里读取:

?

1 <Identity Name="36385XiaowuHu.100280B26F648" Publisher="CN=60BC9EB8-6EF8-44C4-817C-FCE25D428B9B" Version="1.<span style="color: rgb(255, 102, 0);">0.0.18</span>" />

 

在博客园 Universal App 中,Windows Phone 版的设置页面的入口是 BottomAppBar 中定义的

 <AppBarButton x:Name="btn_Setting" Label="设置" Icon="Setting" Click="btn_Setting_Click"/>

按钮提供的。这也是大多数 Windows Phone App 的设置页面的入口。

5

 

除了 AppBarButton 以外,我们还可以通过更快捷的方式直接进入设置的具体页面。例如我们在 BottomAppBar 中添加

 <CommandBar.SecondaryCommands>
                <AppBarButton x:Name="btnAbout" Label="关于本应用" Click="btnAbout_Click" />
</CommandBar.SecondaryCommands>

6

并在后台实现点击事件对应的方法:

 private void btnLogon_Click(object sender, RoutedEventArgs e)
        {
            this.Frame.Navigate(typeof(SettingsPage), new DataModel.SettingNavigationParameter() { targetPivot = TargetPivotItemName.About, targetCss = 0 });
        }

即可直接跳转到对应的关于页面。这样除了统一的设置入口以外,在不同页面添加适应不同页面的不同快捷入口,使得用户可以根据当前页面快速找到对应设置选项。这是一个非常好的实践经验和用户体验,即,在不同上下文时提供不同的设置入口,比如在Reading Page,可以提供“设置字号”菜单进入Setting Page;在Write Comment Page可以提供“登录”菜单进入Setting Page。

设置页面的后台实现与数据保存

所有设置页面的操作,例如对 ToggleButton 的拖动,对 Button 的点击等等,都可以通过填写控件本身提供的事件方法来进行相应的操作,此处就不再赘述。那么当用户进行设置以后,如何保存用户的设置,使得用户每次打开 App 都应用上次保存的设置内容呢?

在 App 中常用的保存数据有 XML 序列化和保存 Setting 字段两种方式,前者主要适用于保存结构化的数据,对于简单的设置数据的保存,我们在博客园应用中使用了后者。

我们在 CNBlogs.DataHelper.DataModel 的命名空间下添加 Setting.cs 用于定义各设置数据。以夜间模式举例,在此类中添加如下定义:

复制代码

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;

namespace CNBlogs.DataHelper.DataModel
{
    public sealed class CNBlogSettings : DataModelBase
    {
        private ApplicationDataContainer settings = Windows.Storage.ApplicationData.Current.LocalSettings;

        const string SettingKey_NightModeTheme = "cnblog_night_mode_theme";

        public bool NightModeTheme
        {
            get
            {
                var obj = this.settings.Values[SettingKey_NightModeTheme];
                return obj == null ? false : (bool)obj;
            }
            set
            {
                this.settings.Values[SettingKey_NightModeTheme] = value;
                base.OnPropertyChanged("NightModeTheme");
            }
        }
    }
}

复制代码

就实现了简单的 NightModeTheme 字段的本地保存。为了保持一致性,还可以将 Setting 类设计为单例模式。

这样,在 ToggleButton 提供的事件方法中,我们可以对 NightModeTheme 字段进行修改,Setting 类会负责读取与保存该字段的内容。

当然,可不可以不通过 C# 代码也能实现对 Setting 字段的修改呢?当然可以。XAML 的数据绑定为此提供了更优雅的解决方案。我们只需要在夜间模式对应的 ToggleButton 中的XAML定义中添加 IsOn="{Binding NightModeTheme, Mode=TwoWay}" 这么一个属性,就可以绑定 ToggleButton 的状态与 Setting 类中 NightModeTheme 的值了。当然,根据 NightModeTheme 的值来进行怎样的操作,如提供夜间模式变换主题状态等操作,还是需要后台代码实现的。

总结

本文介绍对 Windows App 和 Windows Phone App 设置界面的简单设计,并给出了后台代码和数据保存的基本实现。通过这些,Universal App 就可以拥有一个看起来像模像样的设置页面了。至于如何设计更加人性化,更加“高大上”的设计界面,就需要开发者们努力实现了。比如在我们的博客园客户端中的关于界面,实现了一个超出用户预期的小动画。欢迎交流。

 

你可以从这里下载我们分享的源代码:

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

当然更可以直接下载两个App来看效果,但是由于designer介入较晚,所以UI上面还需要完善,我们会持续更新App。

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

纯粹干净的App, 里面绝无广告,请放心使用。

 分享代码,改变世界!

MSDN官方文档:

Quickstart: Add app settings (XAML)

https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh872190.aspx

Guidelines for app settings

https://msdn.microsoft.com/en-us/library/windows/apps/hh770544.aspx

Adding app settings (XAML)

https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh770543.aspx

App certification requirements for the Windows Store

https://msdn.microsoft.com/en-us/library/windows/apps/hh694083.aspx

Loading and saving settings

https://msdn.microsoft.com/en-us/library/windows/apps/dn263230.aspx