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

来源:https://www.cnblogs.com/dino623/archive/2020/01/17/uwp_CompactOverlay_mode.html

1. 什麼是,以及怎麼用畫中畫 Windows 10 Creators Update以後UWP提供了一個新的視圖模式CompactOverlay,中文翻譯成 緊湊的覆蓋層 ?反正大部分時間我們都會稱它為 畫中畫模式 。 上圖中右上角即為進入畫中畫模式的微軟“電影和電視”應用。 可以調用 "Appli ...


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


您的分享是我們最大的動力!

更多相關文章
  • [TOC] MVC "MVC 維基百科,自由的百科全書" MVC 是軟體工程的一種軟體架構模式,它不是具體的技術,而是一種代碼分層的理念,主要體現了職責分離原則。 M Model 模型 V View 視圖 C Controller 控制器 對 MVC 的誤解及緣由 誤解:頁面視圖 = View ,E ...
  • 簡介 Orleans用起來的確很爽,更爽的是咱們有能監控它的工具。 " OrleansDashboard " 這個工具是一個可視化的Silo監控工具,Silo和Grain的活躍狀態一目瞭然,各個介面的響應速度也可以很清晰的統計到。 安裝 使用NuGet引用 然後修改 的配置,添加Dashboard: ...
  • Teigha中實體旋轉 代碼: using (var trans = database.TransactionManager.StartTransaction()) { Entity ent = trans.GetObject(entityId, OpenMode.ForWrite) asEntit ...
  • 什麼是AutoMapper?AutoMapper是一個簡單的小型庫,用於解決一個看似複雜的問題 - 擺脫將一個對象映射到另一個對象的代碼。這種類型的代碼是相當沉悶和無聊的寫,所以為什麼不發明一個工具來為我們做? 我們來看看在.netcore3.1中怎樣使用AutoMapper9.0。 Profile ...
  • 程式處理存放圖片的幾種方式 我的理解有4個: 1:放在項目本身得文件夾中,直接部署到伺服器上 2:存放在磁碟中,然後資料庫中存放路徑,讀取得時候傳路徑。這個適合小項目 3:將圖片轉換成二進位文件,但是不建議這樣做,因為會給資料庫造成壓力。 4:存放在雲存儲器上,也是在資料庫上存地址,不過是雲地址,使 ...
  • 第一部分:面向對象 封裝 繼承(里氏轉換) 多態第二部分:值類型、引用類型、字元串操作第三部分:集合文件操作第四部分:正則表達式第五部分:XML操作第六部分:委托、事件第七部分:反射。 //存儲著我們當前正在運行的進程//Process[] pro = Process.GetProcesses(); ...
  • 在很多時候,我們做一些非常規化的界面的時候,往往需要創建一些用戶控制項,在其中繪製好一些基礎的界面塊,作為後續重覆使用的一個單元,用戶控制項同時也可以封裝處理一些簡單的邏輯。在開發Winform各種類型項目,我都時不時需要定製一些特殊的用戶控制項,以方便在界面模塊中反覆使用。我們一般是在自定義的用戶控制項里... ...
  • C#實現的對兩個Table進行Merge,兩表必須存在至少一個公共欄位作為連接項,否則連接就失去了意義。如下是對兩個table進行Merge的詳細代碼: private void button1_Click(object sender, EventArgs e)//Button點擊觸發事件 { #r ...
一周排行
  • 比如要拆分“呵呵呵90909086676喝喝999”,下麵當type=0返回的是中文字元串“呵呵呵,喝喝”,type=1返回的是數字字元串“90909086676,999”, private string GetStrings(string str,int type=0) { IList<strin ...
  • Swagger一個優秀的Api介面文檔生成工具。Swagger可以可以動態生成Api介面文檔,有效的降低前後端人員關於Api介面的溝通成本,促進項目高效開發。 1、使用NuGet安裝最新的包:Swashbuckle.AspNetCore。 2、編輯項目文件(NetCoreTemplate.Web.c ...
  • 2020 年 7 月 30 日, 由.NET基金會和微軟 將舉辦一個線上和為期一天的活動,包括 微軟 .NET 團隊的演講者以及社區的演講者。本次線上大會 專註.NET框架構建微服務,演講者分享構建和部署雲原生應用程式的最佳實踐、模式、提示和技巧。有關更多信息和隨時瞭解情況:https://focu... ...
  • #abp框架Excel導出——基於vue #1.技術棧 ##1.1 前端採用vue,官方提供 UI套件用的是iview ##1.2 後臺是abp——aspnetboilerplate 即abp v1,https://github.com/aspnetboilerplate/aspnetboilerp ...
  • 前言 本文的文字及圖片來源於網路,僅供學習、交流使用,不具有任何商業用途,版權歸原作者所有,如有問題請及時聯繫我們以作處理。 作者:碧茂大數據 PS:如有需要Python學習資料的小伙伴可以加下方的群去找免費管理員領取 input()輸入 Python提供了 input() 內置函數從標準輸入讀入一 ...
  • 從12年到20年,python以肉眼可見的趨勢超過了java,成為了當今It界人人皆知的編程語言。 python為什麼這麼火? 網路編程語言搜索指數 適合初學者 Python具有語法簡單、語句清晰的特點,這就讓初學者在學習階段可以把精力集中在編程對象和思維方法上。 大佬都在用 Google,YouT ...
  • 在社會上存在一種普遍的對培訓機構的學生一種歧視的現象,具體表現在,比如:當你去公司面試的時候,一旦你說了你是培訓機構出來的,那麼基本上你就涼了,那麼你瞞著不說,然後又通過了面試成功入職,但是以後一旦在公司被髮現有培訓經歷,可能會面臨被降薪,甚至被辭退,培訓機構出來的學生,在用人單位眼裡就是能力低下的 ...
  • from typing import List# 這道題看了大佬寫的代碼,經過自己的理解寫出來了。# 從最外圍的四周找有沒有為O的,如果有的話就進入深搜函數,然後深搜遍歷# 判斷上下左右的位置是否為Oclass Solution: def solve(self, board: List[List[s ...
  • import requests; import re; import os; # 1.請求網頁 header = { "user-agent":'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, li ...
  • import requests; import re; import os; import parsel; 1.請求網頁 header = { "user-agent":'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537. ...