在 UWP 中使用 CommandBar 來迅速添加一組功能按鈕是非常迅速的,是 UWP 中推薦的交互方案之一。也許你能見到 CommandBar 按你所需向下展開,不過可能更多數情況會看到 CommandBar 的展開方向是向上的。
本文將解釋 CommandBar 的展開方向邏輯,並且提供多種方法來解決它展開方向的問題。
本文內容
為什么我們需要更改 CommandBar 的展開方向?
<CommandBar Background="#40000000" ClosedDisplayMode="Compact">
<AppBarButton Icon="Add" Label="添加" ToolTipService.ToolTip="添加一個 RSS 訂閱" />
<AppBarButton Icon="Bullets" Label="編輯" ToolTipService.ToolTip="進入編輯狀態" />
</CommandBar>
看下圖的例子,我們有一個在頂部的 CommandBar,但是它展開的時候方向是向上的,以至於擋住了頂部的標題欄。
▲ CommandBar 在不合適的方向展開
理論上標題欄是擋不住的。不過,由於流暢設計(Fluent Design)的存在,越來越多的應用開始使用自定義的標題欄,以獲得渾然天成的流暢設計效果。而上圖就是其中的一個例子。
我們當然希望在頂部的 CommandBar 其展開方向是向下,所以我們需要找到一些方法。
將 CommandBar 改為向下展開的幾種方法
首先定一個基調:CommandBar 的默認展開方向就是向上,無論你使用哪種方式,本質上都沒有解決其展開方向的問題。
所以以下方法都有可能在你的使用場景下失效,除了大殺器 —— 重寫 Template。
方法一:使用 Page.TopAppBar 屬性
<Page x:Class="Walterlv.Rssman.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.TopAppBar>
<CommandBar Background="#40000000" ClosedDisplayMode="Compact">
<AppBarButton Icon="Add" Label="添加" ToolTipService.ToolTip="添加一個 RSS 訂閱" />
<AppBarButton Icon="Bullets" Label="編輯" ToolTipService.ToolTip="進入編輯狀態" />
</CommandBar>
</Page.TopAppBar>
<Grid>
</Grid>
</Page>
如果你並沒有做一些奇怪的樣式,是一個 Demo 或者是剛開始做的應用,那么此方法應該對你有效。
▲ Page.TopAppBar 中的 CommandBar
看!現在 CommandBar 向下展開了。這就是我們的解決方案之一。
不過,覺得怪怪的是不是?因為我自定義了標題欄,當然不能讓標題欄擋住我的控件啊!
千萬不要嘗試將你的 Page 設置一個 Margin 讓他下移,因為:
▲ 無論你設置到哪個 Page 中,無論 Margin 設為多少,就算是給 Frame 外面的 Grid 設置 Margin,通通都是無效的!Page.TopAppBar 在應用窗口級別的。
正如官網中所描述的那樣:
Command bars can be placed at the top of the app window, at the bottom of the app window, and inline.
方法二:更改布局,使得頂部空間不足以展開 CommandBar
CommandBar 的 ClosedDisplayMode
設為 Compact
時,折疊狀態高度 48,展開狀態高度 60;在設為 Minimal
時,折疊狀態高度 24,展開狀態依然是 60。
▲ 各種模式下的展開和折疊高度
鑒於 CommandBar 僅在空間不足時才會從向上展開變為向下展開,所以我們可以利用頂部空間的距離差來完成方向的修改。
對於 Compact
模式,我們僅能在上方預留不足 12 的尺寸,而對於 Minimal
模式,我們則有不大於 36 的尺寸可以預留。
在我們一開始的例子中,我們需要留出標題欄的高度,而標題欄高度為 32,所以使用 Minimal
模式時,我們的展開方向自然因為頂部空間不足而向下展開。另外,12 像素除了留白以外也沒什么作用,所以實質上 Compact
模式並不能通過這種方式解決展開方向的問題。
▲ 在使用 Minimal 的關閉模式時,可以向下展開
如果你設置的 SecondaryCommand 比較長,那么展開的時候也會占用較多的控件,於是也可以強制 CommandBar 向下展開。
方法三:設置 DefaultLabelPosition 避開展開方向的問題
如果不容易改展開方向,那么不讓 CommandBar 面臨展開方向的問題也是一個不錯的解決方案 —— 為 CommandBar 設置 DefaultLabelPosition
便是這樣的方案。
將 DefaultLabelPosition
屬性設置為 Right
或者 Collapsed
而不是 Bottom
,那么 CommandBar 便不再需要展開這些按鈕了,因為即便展開也不會顯示更多的信息了,除了那個根本不會影響高度的更多項。
▲ 設置為 Collapsed 或者 Right 的 DefaultLabelPosition
方法四:修改 CommandBar 的模板
不得不說這真是一個令人難受的方法,因為定義 CommandBar 模板和樣式的代碼行數有 1400 行左右。但這也是目前依然使用 CommandBar 控件時最好的方案了。
▲ 編輯控件模板的副本
現在,使用 Visual Studio 設計器來幫助我們獲得 CommandBar 的完整默認樣式定義,就像上圖那樣。於是,我們可以閱讀其代碼並修改展開方向了。
代碼很長,為了能夠迅速理解其結構,我將其最關鍵的大綱部分貼到下面:
<ControlTemplate x:Key="CommandBarTemplate1">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="DisplayModeStates">
<VisualStateGroup.Transitions>
<VisualState From="CompactClosed" To="CompactOpenUp" />
<VisualState From="CompactOpenUp" To="CompactClosed" />
<VisualState From="CompactClosed" To="CompactOpenDown" />
<VisualState From="CompactOpenDown" To="CompactClosed" />
<VisualState From="MinimalClosed" To="MinimalOpenUp" />
<VisualState From="MinimalOpenUp" To="MinimalClosed" />
<VisualState From="MinimalClosed" To="MinimalOpenDown" />
<VisualState From="MinimalOpenDown" To="MinimalClosed" />
<VisualState From="HiddenClosed" To="HiddenOpenUp" />
<VisualState From="HiddenOpenUp" To="HiddenClosed" />
<VisualState From="HiddenClosed" To="HiddenOpenDown" />
<VisualState From="HiddenOpenDown" To="HiddenClosed" />
</VisualStateGroup.Transitions>
<VisualState x:Name="CompactClosed" />
<VisualState x:Name="CompactOpenUp" />
<VisualState x:Name="CompactOpenDown" />
<VisualState x:Name="MinimalClosed" />
<VisualState x:Name="MinimalOpenUp" />
<VisualState x:Name="MinimalOpenDown" />
<VisualState x:Name="HiddenClosed" />
<VisualState x:Name="HiddenOpenUp" />
<VisualState x:Name="HiddenOpenDown" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
可以看到,對於每一種 ClosedDisplayMode
,都有三種狀態與之對應 —— Closed、Up 和 Down。當然,Up 就是向上展開時的狀態,Down 就是向下展開時的狀態。而 Closed、Up 和 Down 之間的狀態切換有四種 —— Closed 到 Up、Up 到 Closed、Closed 到 Down 以及 Down 到 Closed。
於是,我們要獲得任何時候都向下展開的能力,我們便需要將所有的 Up 狀態修改成 Down 的狀態。
現在,我們將 將 <VisualState From="CompactClosed" To="CompactOpenDown" />
的代碼復制到 <VisualState From="CompactClosed" To="CompactOpenUp" />
中,<VisualState From="CompactOpenDown" To="CompactClosed" />
內部的代碼復制到 <VisualState From="CompactOpenUp" To="CompactClosed" />
中,將 <VisualState x:Name="CompactOpenDown" />
內的代碼復制到 <VisualState x:Name="CompactOpenUp" />
中。
也就是說,我們將所有 CompactClosed 和 CompactDown 的狀態復制到了 CompactClosed 和 CompactUp 的狀態中。這樣,即便 CommandBar 判定為向上展開,實際上的動畫和交互也都是向下展開的了。
以下是這樣修改后的效果。
▲ 使用樣式更改的展開方向
究竟應該如何修改 CommandBar 的展開方向
在多數情況下,我想我們並沒有特別強烈的需求一定要讓 CommandBar 在頂部依然有空間的情況下展開方向向下。
如果有,那通常也是中大型項目,這時 CommandBar 樣式和模板所占用的那 1400 行左右的代碼也就不顯得多了。
但對於小型個人項目而言,可以考慮修改應用程序的外觀設計來規避這么長的代碼。例如讓 CommandBar 始終顯示或隱藏文字,或者讓 CommandBar 默認為 Minimal
的狀態。
如果你對其他控件有小型樣式的修改需求,可以閱讀我的另一篇文章:UWP 輕量級樣式定義(Lightweight Styling)。