Share via


延長顯示啟動顯示畫面

您可以為應用程式建立延長式啟動顯示畫面,讓啟動顯示畫面的顯示時間變長。 此擴充畫面模仿應用程式啟動時顯示的啟動畫面,但可以自訂。 無論您是想顯示即時載入訊息,還是只是給應用程式額外的時間來準備其初始 UI,擴展的啟動畫面都可以讓您定義啟動體驗。

注意

本主題中的「延長啟動顯示畫面」一詞是指長時間停留在螢幕上的啟動顯示畫面。 這並不表示衍生自 SplashScreen 類別的子類別。

重要 API

本主題中會使用下列 API:

預設啟動顯示畫面建議

請遵循下列建議,確定您的擴充啟動顯示畫面正確模擬預設啟動顯示畫面:

  • 您的擴充啟動畫面頁面應使用 620 x 300 像素的影像,該影像與應用程式清單中為啟動畫面指定的影像 (應用程式的啟動畫面影像) 一致。 在 Microsoft Visual Studio 中,啟動畫面設定儲存在應用程式清單 (Package.appxmanifest 檔案) 中 Visual Assets 標籤的 Splash Screen 部分。
  • 您的擴充啟動畫面應使用與應用程式清單中為啟動畫面指定的背景顏色一致的背景顏色 (您的應用程式的啟動畫面背景)
  • 您的程式代碼應該使用 SplashScreen 類別,將 app 的啟動顯示畫面影像放置在與預設啟動顯示畫面相同的螢幕座標。
  • 您的程式碼應該透過使用 SplashScreen 類別在擴展的初始畫面上重新定位項目來回應視窗大小調整事件 (例如,當螢幕旋轉或您的應用程式移動到螢幕上的另一個應用程式旁邊時)。

使用下列步驟來建立延伸啟動顯示畫面,以有效模擬預設啟動顯示畫面。

Blank Page 專案新增至現有的應用程式

本主題假設你想要使用 C#、Visual Basic 或 C++ 將擴充初始畫面新增至現有通用 Windows 平台 (UWP) 應用程式專案。

  • 在 Visual Studio 中開啟應用程式。
  • 從功能表列中按或開啟專案,然後按一下新增項目。 將出現新增項目對話框。
  • 在此對話框中,將新的空白頁面新增至您的應用程式。 本主題將擴充啟動顯示畫面頁面命名為「ExtendedSplash」。

新增空白頁面專案會產生兩個檔案,一個用於標記 (ExtendedSplash.xaml),另一個用於程式代碼 (ExtendedSplash.xaml.cs)。

擴充啟動顯示畫面的基本 XAML

請遵循下列步驟,將影像和進度控件新增至延伸啟動顯示畫面。

在您的 ExtendedSplash.xaml 檔案中:

  • 變更預設 Grid 元素的背景屬性,以符合您在應用程式清單 (在 Package.appxmanifest 檔案的 Visual Assets 部分) 中為應用程式啟動螢幕設定的背景顏色。 預設啟動顯示畫面色彩為淺灰色 (十六進位值 #464646)。 請注意,當您建立新的空白頁面時,預設會提供此 Grid 元素。 您不需要使用 Grid;這隻是建置延伸啟動顯示畫面的便利基礎。
  • Canvas 元素新增至 Grid。 您將使用此 Canvas 來放置延伸啟動顯示畫面影像。
  • Image 元素新增至 Canvas。 針對您為預設啟動顯示畫面選擇的延伸啟動顯示畫面使用相同的 620 x 300 像素影像。
  • (選擇性) 新增進度控制件,以顯示您的應用程式正在載入的使用者。 本主題會新增 ProgressRing,而不是確定或不確定 的 ProgressBar

下列範例示範具有這些新增和變更的 Grid

    <Grid Background="#464646">
        <Canvas>
            <Image x:Name="extendedSplashImage" Source="Assets/SplashScreen.png"/>
            <ProgressRing Name="splashProgressRing" IsActive="True" Width="20" HorizontalAlignment="Center"></ProgressRing>
        </Canvas>
    </Grid>

注意

本範例會將 ProgressRing寬度設定為 20 像素。 您可以手動將其寬度設定為適用於您的應用程式值,不過,控件不會以小於 20 像素的寬度呈現。

擴充啟動顯示畫面類別的基本程序代碼

每當視窗大小 (僅限 Windows) 或方向變更時,您的延長啟動顯示畫面必須回應。 您使用的圖像的位置必須更新,以便無論視窗如何變化,擴展的初始螢幕看起來都很好。

使用這些步驟來定義方法,以正確顯示您的擴充啟動顯示畫面。

  1. 新增必要的命名空間

    您必須將下列命名空間新增至 ExtendedSplash.xaml.cs,才能存取 SplashScreen 類別、Rect 結構,以及 Window.SizeChanged 事件。

    using Windows.ApplicationModel.Activation;
    using Windows.Foundation;
    using Windows.UI.Core;
    
  2. 建立部分類別並宣告類別變數

    在 ExtendedSplash.xaml.cs 中包含下列程式代碼,以建立部分類別來表示延伸啟動顯示畫面。

    partial class ExtendedSplash : Page
    {
        internal Rect splashImageRect; // Rect to store splash screen image coordinates.
        private SplashScreen splash; // Variable to hold the splash screen object.
        internal bool dismissed = false; // Variable to track splash screen dismissal status.
        internal Frame rootFrame;
    
       // Define methods and constructor
    }
    

    這些類別變數是由數種方法使用。 splashImageRect 變數會儲存系統顯示應用程式啟動顯示畫面影像的座標。 變數 splash 會儲存 SplashScreen 物件,而 dismissed 變數會追蹤系統所顯示的啟動顯示畫面是否已關閉。

  3. 為您的類別定義正確定位影像的建構函式

    以下程式碼定義了擴展啟動畫面類別的建構函數,該構造函數偵聽視窗大小調整事件、在擴展啟動畫面上定位影像和 (可選) 進度控制項、建立導航框架,並呼叫非同步方法來恢復已儲存的會話狀態。

    public ExtendedSplash(SplashScreen splashscreen, bool loadState)
    {
        InitializeComponent();
    
        // Listen for window resize events to reposition the extended splash screen image accordingly.
        // This ensures that the extended splash screen formats properly in response to window resizing.
        Window.Current.SizeChanged += new WindowSizeChangedEventHandler(ExtendedSplash_OnResize);
    
        splash = splashscreen;
        if (splash != null)
        {
            // Register an event handler to be executed when the splash screen has been dismissed.
            splash.Dismissed += new TypedEventHandler<SplashScreen, Object>(DismissedEventHandler);
    
            // Retrieve the window coordinates of the splash screen image.
            splashImageRect = splash.ImageLocation;
            PositionImage();
    
            // If applicable, include a method for positioning a progress control.
            PositionRing();
        }
    
        // Create a Frame to act as the navigation context
        rootFrame = new Frame();            
    }
    

    確保在類別建構函式中註冊您的 Window.SizeChanged 處理程序 (ExtendedSplash_OnResize在範例中),以便您的應用程式將影像正確放置在擴充的初始畫面中。

  4. 定義類別方法,以將影像放置在延伸啟動顯示畫面中

    此程式代碼示範如何使用 類別變數,在延伸啟動顯示畫面頁面上 splashImageRect 放置影像。

    void PositionImage()
    {
        extendedSplashImage.SetValue(Canvas.LeftProperty, splashImageRect.X);
        extendedSplashImage.SetValue(Canvas.TopProperty, splashImageRect.Y);
        extendedSplashImage.Height = splashImageRect.Height;
        extendedSplashImage.Width = splashImageRect.Width;
    }
    
  5. (可選) 定義一個類別方法以在擴展啟動畫面中定位進度控件

    如果您選擇將 ProgressRing 新增至延伸啟動顯示畫面,請將它相對於啟動顯示畫面影像的位置。 新增下列程式代碼以 ExtendedSplash.xaml.cs 將 ProgressRing 32 像素置中於影像下方。

    void PositionRing()
    {
        splashProgressRing.SetValue(Canvas.LeftProperty, splashImageRect.X + (splashImageRect.Width*0.5) - (splashProgressRing.Width*0.5));
        splashProgressRing.SetValue(Canvas.TopProperty, (splashImageRect.Y + splashImageRect.Height + splashImageRect.Height*0.1));
    }
    
  6. 在類別內,定義 Dismissed 事件的處理程式

    在 ExtendedSplash.xaml.cs中,將類別變數設定為 true,以回應 SplashScreen.Dismissed 事件發生的時間dismissed。 如果您的應用程式有設定作業,請將它們新增至此事件處理程式。

    // Include code to be executed when the system has transitioned from the splash screen to the extended splash screen (application's first view).
    void DismissedEventHandler(SplashScreen sender, object e)
    {
        dismissed = true;
    
        // Complete app setup operations here...
    }
    

    完成應用程式設定之後,請離開延伸啟動顯示畫面。 下列程式代碼會定義名為 DismissExtendedSplash 的方法,該方法會巡覽至 MainPage 應用程式 MainPage.xaml 檔案中定義的 。

    async void DismissExtendedSplash()
      {
         await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() =>            {
              rootFrame = new Frame();
              rootFrame.Content = new MainPage(); Window.Current.Content = rootFrame;
            });
      }
    
  7. 在類別內,定義 Window.SizeChanged 事件的處理程式

    準備您的延伸啟動顯示畫面,以在使用者調整視窗大小時重新調整其元素的位置。 此程式代碼會擷取新的座標並重新定位影像,以回應 Window.SizeChanged 事件發生時。 如果您已將進度控件新增至延伸啟動顯示畫面,也請將它重新置放在此事件處理程式內。

    void ExtendedSplash_OnResize(Object sender, WindowSizeChangedEventArgs e)
    {
        // Safely update the extended splash screen image coordinates. This function will be executed when a user resizes the window.
        if (splash != null)
        {
            // Update the coordinates of the splash screen image.
            splashImageRect = splash.ImageLocation;
            PositionImage();
    
            // If applicable, include a method for positioning a progress control.
            // PositionRing();
        }
    }
    

    注意

     在您嘗試取得影像位置之前,請確定類別變數 (splash) 包含有效的 SplashScreen 物件,如範例所示。

     

  8. (選擇性) 新增類別方法以還原已儲存的工作階段狀態

    您在步驟 4:修改啟動啟用處理程式中新增至 OnLaunched 方法的程式代碼,會導致您的應用程式在啟動時顯示延伸啟動顯示畫面。 若要合併擴充啟動顯示畫面類別中與應用程式啟動相關的所有方法,您可以考慮將方法新增至 ExtendedSplash.xaml.cs 檔案,以還原應用程式的狀態。

    void RestoreState(bool loadState)
    {
        if (loadState)
        {
             // code to load your app's state here
        }
    }
    

    當您修改 App.xaml.cs 中的啟動啟動處理程序時,如果應用程式的先前 ApplicationExecutionState已終止,您也會設定為 loadstate true。 如果是,方法會將 RestoreState 應用程式還原為其先前的狀態。 如需應用程式啟動、暫停和終止的概觀,請參閱應用程式生命週期

修改啟動啟用處理程式

啟動您的應用程式時,系統會將啟動顯示畫面資訊傳遞至應用程式的啟動啟用事件處理程式。 您可以使用這項資訊,在延伸啟動顯示畫面頁面上正確定位影像。 您可以從傳遞至您的應用程式 OnLaunched 處理程式的啟用事件自變數取得此啟動顯示畫面資訊 (請參閱args下列程式代碼中的變數)。

如果您尚未覆寫應用程式的 OnLaunched 處理程式,請參閱應用程式生命週期以瞭解如何處理啟用事件。

在 App.xaml.cs 中,新增下列程式代碼來建立及顯示延伸啟動顯示畫面。

protected override void OnLaunched(LaunchActivatedEventArgs args)
{
    if (args.PreviousExecutionState != ApplicationExecutionState.Running)
    {
        bool loadState = (args.PreviousExecutionState == ApplicationExecutionState.Terminated);
        ExtendedSplash extendedSplash = new ExtendedSplash(args.SplashScreen, loadState);
        Window.Current.Content = extendedSplash;
    }

    Window.Current.Activate();
}

完整程式碼

下列程式代碼與先前步驟中顯示的代碼段稍有不同。

  • ExtendedSplash.xaml 包含 DismissSplash 按鈕。 按兩下此按鈕時,事件處理程式會 DismissSplashButton_Click 呼叫 DismissExtendedSplash 方法。 在您的應用程式中,當您的應用程式完成載入資源或初始化其 UI 時呼叫 DismissExtendedSplash
  • 此應用程式也會使用 UWP 應用程式專案範本,其使用 Frame 瀏覽。 因此,在App.xaml.cs中,啟動啟用處理程式 (OnLaunched) 會 rootFrame 定義 ,並使用它來設定應用程式視窗的內容。

ExtendedSplash.xaml

此範例包含 DismissSplash 按鈕,因為它沒有要載入的應用程式資源。 在您的應用程式中,當您的應用程式完成載入資源或準備其初始UI時,會自動關閉延伸啟動顯示畫面。

<Page
    x:Class="SplashScreenExample.ExtendedSplash"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SplashScreenExample"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="#464646">
        <Canvas>
            <Image x:Name="extendedSplashImage" Source="Assets/SplashScreen.png"/>
            <ProgressRing Name="splashProgressRing" IsActive="True" Width="20" HorizontalAlignment="Center"/>
        </Canvas>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Bottom">
            <Button x:Name="DismissSplash" Content="Dismiss extended splash screen" HorizontalAlignment="Center" Click="DismissSplashButton_Click" />
        </StackPanel>
    </Grid>
</Page>

ExtendedSplash.xaml.cs

請注意,從 DismissSplash 按鈕的點擊事件處理程式呼叫 DismissExtendedSplash 方法。 在您的應用程式中,您不需要 DismissSplash 按鈕。 相反地,當您的應用程式完成載入資源時呼叫 DismissExtendedSplash,而您想要瀏覽至其主頁面。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

using Windows.ApplicationModel.Activation;
using SplashScreenExample.Common;
using Windows.UI.Core;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/p/?LinkID=234238

namespace SplashScreenExample
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    partial class ExtendedSplash : Page
    {
        internal Rect splashImageRect; // Rect to store splash screen image coordinates.
        private SplashScreen splash; // Variable to hold the splash screen object.
        internal bool dismissed = false; // Variable to track splash screen dismissal status.
        internal Frame rootFrame;

        public ExtendedSplash(SplashScreen splashscreen, bool loadState)
        {
            InitializeComponent();

            // Listen for window resize events to reposition the extended splash screen image accordingly.
            // This is important to ensure that the extended splash screen is formatted properly in response to snapping, unsnapping, rotation, etc...
            Window.Current.SizeChanged += new WindowSizeChangedEventHandler(ExtendedSplash_OnResize);

            splash = splashscreen;

            if (splash != null)
            {
                // Register an event handler to be executed when the splash screen has been dismissed.
                splash.Dismissed += new TypedEventHandler<SplashScreen, Object>(DismissedEventHandler);

                // Retrieve the window coordinates of the splash screen image.
                splashImageRect = splash.ImageLocation;
                PositionImage();

                // Optional: Add a progress ring to your splash screen to show users that content is loading
                PositionRing();
            }

            // Create a Frame to act as the navigation context
            rootFrame = new Frame();

            // Restore the saved session state if necessary
            RestoreState(loadState);
        }

        void RestoreState(bool loadState)
        {
            if (loadState)
            {
                // TODO: write code to load state
            }
        }

        // Position the extended splash screen image in the same location as the system splash screen image.
        void PositionImage()
        {
            extendedSplashImage.SetValue(Canvas.LeftProperty, splashImageRect.X);
            extendedSplashImage.SetValue(Canvas.TopProperty, splashImageRect.Y);
            extendedSplashImage.Height = splashImageRect.Height;
            extendedSplashImage.Width = splashImageRect.Width;

        }

        void PositionRing()
        {
            splashProgressRing.SetValue(Canvas.LeftProperty, splashImageRect.X + (splashImageRect.Width*0.5) - (splashProgressRing.Width*0.5));
            splashProgressRing.SetValue(Canvas.TopProperty, (splashImageRect.Y + splashImageRect.Height + splashImageRect.Height*0.1));
        }

        void ExtendedSplash_OnResize(Object sender, WindowSizeChangedEventArgs e)
        {
            // Safely update the extended splash screen image coordinates. This function will be fired in response to snapping, unsnapping, rotation, etc...
            if (splash != null)
            {
                // Update the coordinates of the splash screen image.
                splashImageRect = splash.ImageLocation;
                PositionImage();
                PositionRing();
            }
        }

        // Include code to be executed when the system has transitioned from the splash screen to the extended splash screen (application's first view).
        void DismissedEventHandler(SplashScreen sender, object e)
        {
            dismissed = true;

            // Complete app setup operations here...
        }

        void DismissExtendedSplash()
        {
            // Navigate to mainpage
            rootFrame.Navigate(typeof(MainPage));
            // Place the frame in the current Window
            Window.Current.Content = rootFrame;
        }

        void DismissSplashButton_Click(object sender, RoutedEventArgs e)
        {
            DismissExtendedSplash();
        }
    }
}

App.xaml.cs

此專案是使用 Visual Studio 中的 UWP 應用程式空白應用程式 (XAML) 專案範本建立的。 OnNavigationFailedOnSuspending 事件處理程式都會自動產生,而且不需要變更即可實作延伸啟動顯示畫面。 本主題只會變更 OnLaunched

如果您未針對應用程式使用專案範本,請參閱步驟 4:修改啟動啟用處理程式,以取得未使用 OnLaunchedFrame 瀏覽的已修改範例。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Application template is documented at https://go.microsoft.com/fwlink/p/?LinkID=234227

namespace SplashScreenExample
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    sealed partial class App : Application
    {
        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            Microsoft.ApplicationInsights.WindowsAppInitializer.InitializeAsync(
            Microsoft.ApplicationInsights.WindowsCollectors.Metadata |
            Microsoft.ApplicationInsights.WindowsCollectors.Session);
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used such as when the application is launched to open a specific file.
        /// </summary>
        /// <param name="e">Details about the launch request and process.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {
#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();
                // Set the default language
                rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];

                rootFrame.NavigationFailed += OnNavigationFailed;

                //  Display an extended splash screen if app was not previously running.
                if (e.PreviousExecutionState != ApplicationExecutionState.Running)
                {
                    bool loadState = (e.PreviousExecutionState == ApplicationExecutionState.Terminated);
                    ExtendedSplash extendedSplash = new ExtendedSplash(e.SplashScreen, loadState);
                    rootFrame.Content = extendedSplash;
                    Window.Current.Content = rootFrame;
                }
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

        /// <summary>
        /// Invoked when Navigation to a certain page fails
        /// </summary>
        /// <param name="sender">The Frame which failed navigation</param>
        /// <param name="e">Details about the navigation failure</param>
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            // TODO: Save application state and stop any background activity
            deferral.Complete();
        }
    }
}

參考