Marvin's Blog【程式人生】

Ability will never catch up with the demand for it

22 Mar 2020

UWP设计文档阅读笔记(三):自定义标题栏

Design and UI > Shell > Title bar customization

桌面UWP提供有API,可以用来自定义窗口的标题栏区域。这些API可以让你改变标题栏的颜色,或者将UI内容放置到标题栏上。

如果只是想修改标题栏颜色,设置ApplicationViewTitleBar的相关部属即可。

如果想更深入自定义标题栏,比如将背景扩展到标题栏区域,应用程序需要提供一些原先由系统提供的功能,比如绘制标题,定义拖拽区域等等。按键区域(最大化、最小化、关闭)依然可以由系统提供。

颜色自定义可以通过XAML,DirectX或者HTML等方式。深度自定义只能通过XAML。

修改标题栏颜色的例子:

// using Windows.UI.ViewManagement;

var titleBar = ApplicationView.GetForCurrentView().TitleBar;

// Set active window colors
titleBar.ForegroundColor = Windows.UI.Colors.White;
titleBar.BackgroundColor = Windows.UI.Colors.Green;
...

上面的代码放置在OnLaunched方法中,在执行完Window.Activate之后。

Windows Community Toolkit扩展了XAML,让你可以用XAML指定颜色属性。

修改标题栏的一些注意事项:

  • 关闭按键的悬停和按下状态的颜色是无法修改的
  • 按键的自定义颜色对回退按键也有效(See Navigation history and backwards navigation
  • 如果将颜色设置为null,则意味着使用系统颜色
  • 无法设置颜色的透明度,颜色的alpha通道会被忽略

Windows系统可以允许用户设置一个accent color到标题栏。因此,如果修改了标题栏颜色,最好指定所有的颜色集合,否则可能被用户自定义的颜色所干扰。

深度自定义标题栏的情况下,相当于把窗口的内容区域扩展到了标题栏。应用程序负责处理标题栏(除按键区域外)的输入处理。

要深度自定义标题栏,只要将CoreApplicationViewTitleBar.ExtendViewIntoTitleBar设置成true即可:

// using Windows.ApplicationModel.Core;

// Hide default title bar.
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.ExtendViewIntoTitleBar = true;

上面的设置可以在OnLaunched的时候或者在第一个页面中设置。

这个设置是持久有效的,即便应用关闭后重新打开也是如此。(可能是保存在注册表中的)。

拖拽区域让用户可以用鼠标移动窗口。可以通过Window.SetTitleBar来传入一个UIElement来定义拖拽区域

Full customization example提供了一个完整的例子。

因为UWP支持多页切换,可以在根页面中定义工具栏所用的XAML,也可以在每个子页面中定义。如果Window.SetTitleBar传入的值是null,那么则会使用系统默认行为。

自定义标题栏区域必须能够接受点击测试(hit test),这意味着有一些UI元素的背景必须设置成透明的。参考VisualTreeHelper.FindElementsInHostCoordinates 。一个使用Grid做拖曳区域的例子:

<Grid x:Name="AppTitleBar" Background="Transparent">

如果不设置Window.SetTitleBar,或者设置为null,系统会设置一个默认拖曳区域,与窗口等宽,与按键区域等高。如果设置了非null的Window.SetTitleBar,那么前面的默认拖曳区域就会缩小成一个按键大小,并紧贴在按键区域的左边。

按键(回退,最小化、最大化、关闭)区域在标题栏左边或者右边(取决于语言的阅读方向),这是系统的保留区域。通过CoreApplicationViewTitleBar 类的SystemOverlayLeftInset 或者SystemOverlayRightInset 可以获取宽度;通过Height 可以获取高度。如果你的UI覆盖到了系统按键区域,那么不好意思,这部分UI不会收到任务输入事件,输入事件依然传递给所在的按键。

系统按键区域的大小可能会发生改变(不如不再显示回退按键),通过LayoutMetricsChanged 可以获取改变通知。

可以把交互性的内容(按键、菜单、搜索框等等)放置在标题栏上。但是有一些规则需要遵守,否则这些内容得不到输入:

  • 依然必须使用Window.SetTitleBar来设置一个拖曳区域,要不系统依然会把整个标题栏当作拖曳区域,从而交互性内容无法获得用户输入
  • 把交互性内容叠加到自定义的拖曳区域之上(使其拥有更高的z-order),不要将自定义内容作为拖曳区域的子内容,因为拖曳区域的所有交互都是系统处理的

将背景扩展到标题栏以后,按键区域的按键背景色可以设置为透明,以显示应用的背景,下面几种颜色部属是可以设置成透明的:

  • ButtonBackgroundColor
  • ButtonHoverBackgroundColor
  • ButtonPressedBackgroundColor
  • ButtonInactiveBackgroundColor

完全透明可以通过Colors.Transparent 设置,部分透明需要设置颜色的alph通道值。

标题栏在全屏模式或者平板模式下可以被隐藏。全屏模式由应用自身控制ApplicationView.IsFullScreenMode;平板模式Tablet mode则是跟设备相关。可以订阅CoreApplicationViewTitleBar.IsVisibleChanged事件来得知隐藏标题栏的时机。

Full customization example,可以看到一个完整的例子。

(完)

2020-11-15更新

注意ApplicationViewTitleBar和CoreApplicationViewTitleBar是两个不同的类型,前者的辖属可以用来设置颜色,后者则可以设置是否将窗口内容扩展到标题栏。

WindowsCommunityToolkit有一ThemeListener类型,而UWP没有。

uwp: changing titleBar.ButtonForegroundColor with ThemeResource得知可以通过订阅UISettings的事件来获取系统颜色改变的消息通知。Martin Zikmund在其博客文章Observing system color changes in UWP apps中作了更多介绍。还有一个例子在Github。monaco-editor-uwp的ThemeListener.cs则通过订阅AccessibilitySettings和UISettings来判断主题的变化。

Application.RequestedTheme是只读属性,如果设置了,会发出NotSupportedException错误。

其他参考

(更新完)

Categories

Tags

comments powered by Disqus