[UWP]用畫中畫模式(CompactOverlay Mode)讓用總在最前端顯示

1. 什麼是,以及怎麼用畫中畫

Windows 10 Creators Update以後UWP提供了一個新的視圖模式CompactOverlay,中文翻譯成 緊湊的覆蓋層?反正大部分時間我們都會稱它爲畫中畫模式

上圖中右上角即爲進入畫中畫模式的微軟“電影和電視”應用。

可以調用ApplicationView.TryEnterViewModeAsync函數進入或退出CompactOverlayer模式:

//進入CompactOverlay模式
await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.CompactOverlay);

//返回默認模式
await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.Default);

還可以使用ViewModePreferences控制進入CompactOverlay時窗口的大小:

//進入CompactOverlay模式並將窗體設置爲 200 x 200 像素
var preferences = ViewModePreferences.CreateDefault(ApplicationViewMode.CompactOverlay);
preferences.CustomSize = new Windows.Foundation.Size(200, 200);
await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.CompactOverlay, preferences);

//返回默認模式
var preferences = ViewModePreferences.CreateDefault(ApplicationViewMode.Default);
await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.Default, preferences);

進入CompactOverlay模式後,窗體首先縮小並移動到屏幕右上方,並且有以下行爲:

• 窗口置於頂層;
• 最大化、最小化按鈕消失;
• 標題欄會在失去焦點並且鼠標離開後幾秒鐘消失;
• 使用`Window.Current.SetTitleBar`設置爲標題欄元素的內容也會在鼠標離開後消失;
• 可以改變窗口大小,但只能在 150 x 150 到 500 x 500 之間改變;
• 雖然標題欄消失,但左下右三個邊框仍在;

因爲尺寸有限制,所以超過 150 x 150 到 500 x 500 這個範圍的ViewModePreferences.CustomSize不會生效,會取最接近範圍的值。例如使用 700 x 500 會出現 500 x 500 的窗口。

2. 通過自定義StateTrigger響應畫中畫模式

上一篇文章介紹過如何使用AdaptiveTrigger實現響應式佈局,CompactOverlay的情況更加極端,畢竟有可能從1920 x 1050突然變成150 x 150。爲了應對這種情況,我自定義了一個StateTrigger,根據ApplicationView.ViewMode的值判斷是否激活當前的State。這個類繼承自StateTriggerBase,在監視的FrameworkElement的SizeChanged事件中調用SetActive改變State的激活狀態。具體代碼及使用方式如下:

public class IsCompactOverlayModeTrigger : StateTriggerBase
{
    private FrameworkElement _targetElement;

    public FrameworkElement TargetElement
    {
        get
        {
            return _targetElement;
        }
        set
        {
            if (_targetElement != null)
            {
                _targetElement.SizeChanged -= OnSizeChanged;
            }
            _targetElement = value;
            _targetElement.SizeChanged += OnSizeChanged;
        }
    }

    private void OnSizeChanged(object sender, SizeChangedEventArgs e)
    {
        var view = ApplicationView.GetForCurrentView();
        SetActive(view.ViewMode == ApplicationViewMode.CompactOverlay);
    }
}
<VisualStateManager.VisualStateGroups>
    <VisualStateGroup>
        <VisualState>
            <VisualState.StateTriggers>
                <helpers:IsCompactOverlayModeTrigger TargetElement="{x:Bind}" />
            </VisualState.StateTriggers>
            <VisualState.Setters>
                <Setter Target="CompactView.Opacity"
                        Value="1" />
                <Setter Target="CompactView.IsHitTestVisible"
                        Value="True" />
                <Setter Target="NormalView.Opacity"
                        Value="0" />
                <Setter Target="NormalView.IsHitTestVisible"
                        Value="False" />
            </VisualState.Setters>
        </VisualState>
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

雖然前一篇文章介紹了使用Visibility改變視圖,但使用了ImplicitAnimation的話改變Visibility會觸發動畫,所以有時我會使用Opacity和IsHitTestVisible來顯示/隱藏UI元素。

3. 或者索性導航到新的頁面

使用 StateTrigger畢竟還是有些繁瑣,大部分情況下需要用到畫中畫模式的應用,CompactOverlay的視圖都是固定的那幾個,所以可以直接導航到一個新頁面。

private async void OnEnterDefault(object sender, RoutedEventArgs e)
{
    var preferences = ViewModePreferences.CreateDefault(ApplicationViewMode.Default);
    await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.Default, preferences);
}

private async void OnEnterCompactOverlay(object sender, RoutedEventArgs e)
{
    var preferences = ViewModePreferences.CreateDefault(ApplicationViewMode.CompactOverlay);
    preferences.CustomSize = new Windows.Foundation.Size(150, 150);
    await ApplicationView.GetForCurrentView().TryEnterViewModeAsync(ApplicationViewMode.CompactOverlay, preferences);
    Frame.Navigate(typeof(CompactPage), null, new SuppressNavigationTransitionInfo());
}

這時候記得要使用SuppressNavigationTransitionInfo暫停導航的過渡動畫,否則會很難看。

4. 結語

CompactOverlay mode – aka Picture-in-Picture

上面這篇文章還給出了更多有用的代碼:如何判斷是否支持CompactOverlay及如何在多視圖模式下使用。但我沒有用到就不再贅述了,有興趣可以參考這個文章。

畫中畫模式對我的番茄鍾應用很重要。雖然我很喜歡在第二個屏幕上使用番茄鍾,一來不佔用我的工作區域,二來可以提醒別人我正在專注工作不要打擾,但對很多隻有一個屏幕的用戶來說畫中畫模式更加實用。關於畫中畫模式的更多信息可以參考下面給出的網站。

5. 參考

ApplicationView Class (Windows.UI.ViewManagement) - Windows UWP applications Microsoft Docs

ApplicationViewMode Enum (Windows.UI.ViewManagement) - Windows UWP applications Microsoft Docs

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章