延长显示初始屏幕的时间

通过为你的应用创建延长的初始屏幕,延长显示初始屏幕的时间。 此扩展屏幕模仿启动应用时显示的初始屏幕,但可以自定义。 无论是显示实时加载信息还是只是为应用提供额外的时间来准备其初始 UI,扩展的初始屏幕都允许你定义启动体验。

注意

本主题中的短语“延长的初始屏幕”是指在屏幕上保留延长时间的初始屏幕。 这并不意味着派生自 SplashScreen 类的子类。

重要的 API

本主题使用以下 API:

默认初始屏幕建议

请遵循以下建议,确保延长的初始屏幕准确模仿默认初始屏幕:

  • 延长的初始屏幕页面应使用 620 x 300 像素的图像,该图像与应用清单中为初始屏幕指定的图像(应用的初始屏幕图像)一致。 在 Microsoft Visual Studio 中,初始屏幕设置存储在应用清单(Package.appxmanifest 文件)的“视觉资产”选项卡的初始屏幕部分
  • 延长的初始屏幕应使用与应用清单中初始屏幕指定的背景色一致的背景色(应用的初始屏幕背景)。
  • 你的代码应使用 SplashScreen 类将应用的初始屏幕图像放置在默认初始屏幕所在的同一屏幕坐标处。
  • 你的代码应响应窗口大小事件(例如,当屏幕旋转或应用在屏幕上移动到另一个应用旁边时),方法是使用 SplashScreen 类重新定位延长的初始屏幕上的项目。

使用以下步骤创建可有效模仿默认初始屏幕的延长初始屏幕。

空白页 项添加到现有应用

本主题假定你想要使用 C#、Visual Basic 或 C++ 将扩展的初始屏幕添加到现有 通用 Windows 平台 (UWP) 应用项目。

  • 在 Visual Studio 中打开应用程序。
  • 从菜单栏中按或打开 Project ,然后单击“ 添加新项”。 将显示“ 添加新项 ”对话框。
  • 在此对话框中,向 应用添加新的空白页 。 本主题将延长的初始屏幕页面命名为“ExtendedSplash”。

添加空白页项将生成两个文件,一个用于标记(ExtendedSplash.xaml),另一个用于代码(ExtendedSplash.xaml.cs)。

扩展初始屏幕的基本 XAML

按照以下步骤将图像和进度控件添加到延长的初始屏幕。

在 ExtendedSplash.xaml 文件中:

  • 更改默认 Grid 元素的背景属性,以匹配在应用清单中为应用的初始屏幕设置的背景色(在 Package.appxmanifest 文件的“视觉资产”部分)。 默认的初始屏幕颜色为浅灰色(十六进制值为 #464646)。 请注意,创建新的空白页,默认情况下会提供此 Grid 元素。 你不必使用 网格;它只是一个方便的基础,用于生成延长的初始屏幕。
  • Canvas 元素添加到 网格。 你将使用此 Canvas 定位延长的初始屏幕图像。
  • Image 元素添加到 Canvas。 对为默认初始屏幕选择的延长初始屏幕使用相同的 620 x 300 像素图像。
  • (可选)添加进度控件以显示应用正在加载的用户。 本主题添加 ProgressRing,而不是确定或不确定 ProgressBar

以下示例演示了包含这些添加和更改的网格

    <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. 在类中,定义已消除事件的处理程序

    在ExtendedSplash.xaml.cs中,通过将类变量设置为 dismissed true 来响应 SplashScreen.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 应用项目模板,该模板使用 框架 导航。 因此,在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

请注意 DismissExtendedSplash 方法将从 DismissSplash 按钮的单击事件处理程序中调用。 在你的应用中,不需要按钮 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)”项目模板创建的。 OnNavigationFailed OnSuspending自动生成事件处理程序,无需更改即可实现延长的初始屏幕。 本主题仅修改 OnLaunched

如果未对应用使用项目模板,请参阅步骤 4:修改启动激活处理程序,以获取未使用 Frame 导航的已OnLaunched修改示例。

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();
        }
    }
}

引用