將 UWP 中 CommandBar 的展開方向改為向下展開
在 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 的關閉模式時,可以向下展開
方法三:設定 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
的狀態。
如果你對其他控制元件有小型樣式的修改需求,可以閱讀我的另一篇文章: ofollow,noindex" target="_blank">UWP 輕量級樣式定義(Lightweight Styling) 。