UWP中实现自定义标题栏
0x00 起因
在UWP开发中,有时候我们希望实现自定义标题栏,例如在标题栏中加入搜索框、按钮之类的控件。搜了下资料居然在一个日文网站找到了一篇介绍这个主题的文章:
http://www.atmarkit.co.jp/ait/articles/1510/14/news022.html
看了下本想着翻译过来分享,但有些地方说的不是特别明确,所以自己实现了下,结合自己的体会总结了这篇文章。
0x01 UWP中的标题栏
一个普通的UWP窗口如下图所示:
我们可以通过两种方式获取不同的标题栏对象,不同对象操作侧重点不同。
var coreTitleBar = Windows.ApplicationModel.Core.CoreApplication.GetCurrentView().TitleBar;
这种方式获取的是一个CoreApplicationViewTitleBar对象,主要控制标题栏扩展等相关功能。后面的coreTitleBar指的就是这个对象。
var appTitleBar = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView().TitleBar;
这种方式获取的是一个ApplicationViewTitleBar对象,主要用于控制标题栏背景色,最小化、最大化、关闭等按钮的颜色、背景色等。后面的appTitleBar指的就是这个对象。
我们自定义标题栏时这两个对象都会用到。
0x02 实现自定义标题栏
coreTitleBar中有一个属性为ExtendViewIntoTitleBar,将其设置为true就允许将我们在窗体中用XAML定义的视图扩展至标题栏区域
coreTitleBar.ExtendViewIntoTitleBar = true;
这个设置后标题栏原有的地方就消失了,我们定义的试图扩展了过去,如下图所示:
看上去离我们的目标近了一些,标题栏消失了,我们在XAML中定义的Grid上移占据了原有标题栏的位置,原有的appTitleBar上的最大化、最小化、关闭按钮都可用。如果只是一副图片扩展至标题栏用作背景的话貌似可以了,不过我们希望在标题栏上加个搜索栏,所以还是存在几个问题的:
appTitleBar的背景色不协调。
要解决这个问题,我们需要把appTitleBar上按钮的背景色设置为透明:
appTitleBar.ButtonBackgroundColor = Colors.Transparent;
设置后窗体就变成这样了:
按钮背景色变成了透明,但系统标题栏上的按钮和我们自定义标题栏上的搜索框重叠了。要解决这个问题我们可以利用coreTitleBar上的属性SystemOverlayLeftInset和SystemOverlayRightInset,分别表示了coreTitleBar嵌入时的左边距和右边距,我们可以通过设置自定义标题栏的Padding属性达到目的:
//TitleBar为我们自己的标题栏 TitleBar.Height = coreTitleBar.Height; TitleBar.Padding = new Thickness( coreTitleBar.SystemOverlayLeftInset, 0, coreTitleBar.SystemOverlayRightInset, 0 );
那么在什么时候进行这个设置比较好呢,coreTitleBar有一个事件叫做LayoutMetricsChanged,当页面布局发生变化时触发,例如屏幕旋转导致页面重新布局就会触发这个事件。我们可以吧标题栏Padding属性的设置放在这个事件里。设置好后运行程序标题栏如下图所示:
这样似乎好多了,但是当我想在搜索栏输入点内容时发现根本点不进去啊,放大镜按钮也没法点,按住搜索栏还能拖动窗口,看来是我们自己的标题栏被系统标题栏遮挡在下面了。
大概就是上图这么一种感觉。
对于这个问题,我们可以使用Window对象中的SetTitleBar()方法只把文字区域设置为标题栏:
Window.Current.SetTitleBar(TitleText);
其中TitleText是我们自定义标题栏中的文本控件的区域,这个方法就把TitleText这个控件设置为了标题栏。效果就是TitleText控件可以拖动窗体,双击可以最大化/恢复等。这样其他需要接收输入的控件就不属于标题栏,就可以正常接收输入了。
另外我还考虑了一种方式就是重叠两层Grid,底层通过SetTitleBar设置为标题栏,放置不需要接收输入的控件如文本、图片等,上层放置需要接收输入的控件,如TextBox等,不过没有实际测试。
除此之外还可以考虑给标题栏加入返回按钮,按钮调用Frame.GoBack()方法,根据Frame.CanGoBack属性决定返回按钮是否显示。这个也很容易实现,就不作说明了。
程序最后运行效果如图所示,其中手机终端本身就不显示标题栏
0x03 相关下载
https://github.com/durow/TestArea/tree/master/UWPTest/TitleBarTest