初始屏幕

Download Sample下载示例

Android 应用需要一些时间才能启动,尤其是当相应应用首次在设备上启动时。 初始屏幕可能会向用户显示启动进度或指示品牌。

概述

Android 应用需要一些时间才能启动,尤其是在首次在设备上运行时(这有时称为“冷启动”)。 初始屏幕可能会向用户显示启动进度,或者显示品牌信息来标识和推广应用程序。

本指南讨论了在 Android 应用程序中实现初始屏幕的一种方法。 其中包含以下主题:

  1. 为初始屏幕创建可绘制资源。

  2. 定义将显示可绘制资源的新主题。

  3. 向应用程序添加新的活动,该活动将用作上一步中创建的主题所定义的初始屏幕。

Example Xamarin logo splash screen followed by app screen

要求

本指南假设应用程序面向的是 Android API 21 级或更高级别。 应用程序还必须将“Xamarin.Android.Support.v4”和“Xamarin.Android.Support.v7.AppCompat”NuGet 包添加到项目中

本指南中的所有代码和 XML 都可以在本指南的 SplashScreen 示例项目中找到。

实现初始屏幕

呈现和显示初始屏幕的最快方法是创建自定义主题并将其应用于展示初始屏幕的活动。 呈现活动时,它将加载主题,并将可绘制资源(由主题引用)应用于活动的背景。 此方法无需创建布局文件。

初始屏幕将作为显示品牌可绘制资源、执行任何初始化和启动任何任务的活动实现。 应用启动后,初始屏幕活动将启动主活动,并从应用程序后退堆栈中移除自身。

为初始屏幕创建可绘制资源

初始屏幕将在初始屏幕活动的背景中显示 XML 可绘制资源。 必须使用位图图像(如 PNG 或 JPG)来显示图像。

示例应用程序定义了一个名为“splash_screen.xml”的可绘制资源。 此可绘制资源使用层列表将初始屏幕图像居中显示在应用程序中,如以下 xml 所示:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <item>
    <color android:color="@color/splash_background"/>
  </item>
  <item>
    <bitmap
        android:src="@drawable/splash_logo"
        android:tileMode="disabled"
        android:gravity="center"/>
  </item>
</layer-list>

layer-list 将初始图像居中显示在 @color/splash_background 资源指定的背景色上。 示例应用程序在 Resources/values/colors.xml 文件中定义了此颜色:

<?xml version="1.0" encoding="utf-8"?>
<resources>
  ...
  <color name="splash_background">#FFFFFF</color>
</resources>

有关 Drawable 对象的详细信息,请参阅有关 Android 可绘制资源的 Google 文档

实现主题

若要为初始屏幕活动创建自定义主题,请编辑(或添加)文件 values/styles.xml,并为初始屏幕创建新的 style 元素。 下面显示了一个示例文件“values/style.xml”,其 style 名为“MyTheme.Splash”:

<resources>
  <style name="MyTheme.Base" parent="Theme.AppCompat.Light">
  </style>

  <style name="MyTheme" parent="MyTheme.Base">
  </style>

  <style name="MyTheme.Splash" parent ="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowBackground">@drawable/splash_screen</item>
    <item name="android:windowNoTitle">true</item>  
    <item name="android:windowFullscreen">true</item>  
    <item name="android:windowContentOverlay">@null</item>  
    <item name="android:windowActionBar">true</item>  
  </style>
</resources>

MyTheme.Splash 非常简单 – 它声明了窗口背景,从窗口中显式移除了标题栏,并声明它是全屏的。 如果要创建一个在初始活动扩大第一个布局之前模拟应用 UI 的初始屏幕,可以在样式定义中使用 windowContentOverlay 而不是 windowBackground。 在这种情况下,还必须修改 splash_screen.xml 可绘制资源,使其显示模拟的 UI。

创建初始活动

现在,我们需要一个可供 Android 启动的新活动,其中包含初始图像并将执行任何启动任务。 以下代码是完整的初始屏幕实现的示例:

[Activity(Theme = "@style/MyTheme.Splash", MainLauncher = true, NoHistory = true)]
public class SplashActivity : AppCompatActivity
{
    static readonly string TAG = "X:" + typeof(SplashActivity).Name;

    public override void OnCreate(Bundle savedInstanceState, PersistableBundle persistentState)
    {
        base.OnCreate(savedInstanceState, persistentState);
        Log.Debug(TAG, "SplashActivity.OnCreate");
    }

    // Launches the startup task
    protected override void OnResume()
    {
        base.OnResume();
        Task startupWork = new Task(() => { SimulateStartup(); });
        startupWork.Start();
    }

    // Simulates background work that happens behind the splash screen
    async void SimulateStartup ()
    {
        Log.Debug(TAG, "Performing some startup work that takes a bit of time.");
        await Task.Delay (8000); // Simulate a bit of startup work.
        Log.Debug(TAG, "Startup work is finished - starting MainActivity.");
        StartActivity(new Intent(Application.Context, typeof (MainActivity)));
    }
}

SplashActivity 显式使用了在上一部分中创建的主题,以替代应用程序的默认主题。 无需在 OnCreate 中加载布局,因为主题已将一个可绘制资源声明为背景。

请务必设置 NoHistory=true 属性,以从后退堆栈中移除活动。 若要防止后退按钮取消启动过程,还可以替代 OnBackPressed,使其不执行任何操作:

public override void OnBackPressed() { }

启动工作将在 OnResume 中异步执行。 这是必要的,因为这样启动工作就不会减慢或延迟启动屏幕的显示。 该工作完成后,SplashActivity 将启动 MainActivity,用户可以开始与应用进行交互。

通过将 MainLauncher 属性设置为 true,可将此新 SplashActivity 设置为应用程序的启动器活动。 由于 SplashActivity 现在是启动器活动,因此必须编辑 MainActivity.cs,并从 MainActivity 中移除 MainLauncher 属性:

[Activity(Label = "@string/ApplicationName")]
public class MainActivity : AppCompatActivity
{
    // Code omitted for brevity
}

横屏模式

前面步骤中实现的初始屏幕将在竖屏和横屏模式下正确显示。 但是,在某些情况下,有必要分别为竖屏和横屏模式设置单独的初始屏幕(例如,如果初始图像为全屏)。

若要添加针对横屏模式的初始屏幕,请使用以下步骤:

  1. 在 Resources/drawable 文件夹中,添加要使用的初始屏幕图像的横屏版本。 在此示例中,splash_logo_land.png 是上述示例中使用的徽标的横屏版本(它使用白色字母而不是蓝色)

  2. 在 Resources/drawable 文件夹中,创建前面定义的 layer-list 可绘制资源的横屏版本(例如,splash_screen_land.xml)。 在此文件中,将位图路径设置为初始屏幕图像的横屏版本。 在以下示例中,splash_screen_land.xml 使用了 splash_logo_land.png:

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
      <item>
        <color android:color="@color/splash_background"/>
      </item>
      <item>
        <bitmap
            android:src="@drawable/splash_logo_land"
            android:tileMode="disabled"
            android:gravity="center"/>
      </item>
    </layer-list>
    
  3. 创建 Resources/values-land 文件夹(如果尚不存在)

  4. 将文件 colors.xml 和 style.xml 添加到 values-land(可以复制现有的 values/colors.xml 和 values/style.xml 文件并对其进行修改)

  5. 修改 values-land/style.xml,使其为 windowBackground 使用可绘制资源的横屏版本。 在此示例中,使用了 splash_screen_land.xml

    <resources>
      <style name="MyTheme.Base" parent="Theme.AppCompat.Light">
      </style>
        <style name="MyTheme" parent="MyTheme.Base">
      </style>
      <style name="MyTheme.Splash" parent ="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowBackground">@drawable/splash_screen_land</item>
        <item name="android:windowNoTitle">true</item>  
        <item name="android:windowFullscreen">true</item>  
        <item name="android:windowContentOverlay">@null</item>  
        <item name="android:windowActionBar">true</item>  
      </style>
    </resources>
    
  6. 修改 values-land/colors.xml 以配置要用于初始屏幕横屏版本的颜色。 在此示例中,初始屏幕背景色在横屏模式下更改为了蓝色:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
      <color name="primary">#2196F3</color>
      <color name="primaryDark">#1976D2</color>
      <color name="accent">#FFC107</color>
      <color name="window_background">#F5F5F5</color>
      <color name="splash_background">#3498DB</color>
    </resources>
    
  7. 再次生成并运行应用。 请将设备旋转到横屏模式,直至初始屏幕显示完毕。 初始屏幕将更改为横屏版本:

    Rotation of splash screen to landscape mode

请注意,使用横屏模式初始屏幕并不总能提供无缝体验。 默认情况下,Android 会以竖屏模式启动应用,然后将其转换为横屏模式,即使设备已处于横屏模式也是如此。 因此,如果在设备处于横屏模式时启动应用,设备会短暂显示竖屏的初始屏幕,然后以动画形式完成从竖屏到横屏初始屏幕的旋转。 遗憾的是,即使在初始活动标志中指定了 ScreenOrientation = Android.Content.PM.ScreenOrientation.Landscape 时,也会在开始时发生这种从竖屏到横屏的转换。 解决此限制的最佳方法是创建一个在竖屏和横屏模式下均可正确呈现的初始屏幕图像。

总结

本指南讨论了在 Xamarin.Android 应用程序中实现初始屏幕的一种方法,即将自定义主题应用于启动活动。