离子和电容器 - Android 启动画面响应

Ionic & Capacitor - Android Splash Screen Responsiveness

上下文

这与启动画面图像的响应有关,根据我的研究,这只是因为 Capacitor Docs - Splash Screen 缺少文档。

问题

问题是在实现capacitor的splash screen插件时出现的。通常,此实现是在您创建整个项目时从头开始的。但是,它在具有 拉伸 宽高比(例如 Google Pixel 2 XL)或具有 fat 宽高比(例如 iPad Pro)。甚至在某些情况下启动画面图像会四处移动或shrinks/expands(加载时)。

视觉解释

换句话说,本机实现导致初始屏幕图像如下图所示。如果设备被拉伸或变胖,则图像纵横比不会保留。

如果出现两次启动画面(闪烁),请在 style.xml (android)

中尝试此操作
<item name="android:background">@drawable/splash</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">@null</item>

如果您使用纯色作为初始屏幕的背景,其他帖子中建议的解决方案可能适合您,但如果您使用复杂的图像(如渐变),则需要了解以下内容:

如果您想在启动画面和应用程序之间无缝过渡,您需要安装 @capacitor/splash-screen,因为 Android <item name="android:background">@drawable/splash</item> 不允许您淡出启动画面,此外,当 Android 初始屏幕被您的 Ionic 应用程序替换时,您将在呈现 WebView 时遇到短暂的空白屏幕。

@capacitor/splash-screen 允许您自行选择何时隐藏闪屏以及淡出需要多长时间,从而减轻这种情况。

@capacitor/splash-screen 不会替换本机 Android 启动画面 <item name="android:background">@drawable/splash</item>,而是会在 Ionic App 打开后立即创建 Android ImageView (在本机启动画面之后)然后淡出到 WebView。

您可以通过为本机启动画面设置 <item name="android:background">@null</item> 来隐藏本机 Android 启动画面以仅使用 @capacitor/splash-screen 启动画面,但这被认为是一种不好的做法,因为它每次启动应用程序时都会给人一种闲逛片刻的错觉(创建 Ionic 应用程序并在屏幕上显示所需的时间)。

最后,如果你想让原生 Android 启动画面覆盖整个屏幕并保持其宽高比,这是不可能的(至少在 Android 11 和更早版本中),你只能在应用程序启动后使用 ImageView 执行此操作。

所以...您可以采取以下措施来缓解这种情况:

首先,确保本机 Android 启动画面和 @capacitor/splash-screen 创建的启动画面的配置相同,这样当它从第一个到第二个。

然后,您必须将启动画面分成 2 层,一层用于背景(可以拉伸以填充视口而不保持其纵横比),一层用于您的徽标(或其他元素应该居中并保持其纵横比)。

然后,为您的初始屏幕创建一个自定义可绘制对象(即 drawable/launch_splash.xml),这将允许您创建一个具有任意层数的初始屏幕(在我们的例子中) 2,一张做背景,一张做logo)。

最后,使用此自定义可绘制对象代替原始启动画面。

这是我所做的完整示例:

capacitor.config.ts

const config: CapacitorConfig = {
  // ...
  plugins: {
    // ...
    SplashScreen: {
      launchAutoHide: false,
      androidSplashResourceName: 'launch_splash',
    },
  },
};

(确保在对 capacitor.config.ts 进行任何更改后重建您的应用程序,或自行将更改报告给 capacitor.config.json 文件)。

android/app/src/main/assets/capacitor.config.json

{
  // ...
  "plugins": {
    // ...
    "SplashScreen": {
      "launchAutoHide": false,
      "androidSplashResourceName": "launch_splash"
    }
  }
}

android/app/src/main/res/values/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

  <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
  </style>

  <style name="AppTheme.NoActionBar" parent="Theme.AppCompat.NoActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
    <item name="android:background">@null</item>
  </style>

  <style name="AppTheme.NoActionBarLaunch" parent="AppTheme.NoActionBar">
    <item name="android:background">@drawable/launch_splash</item> <!-- launch_splash -->
  </style>

</resources>

android/app/src/main/res/drawable/launch_splash.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
  <!-- You can add as many layer as you want as long as they are drawable bitmaps or vectors -->
  <item android:drawable="@drawable/ic_launcher_background"/> <!-- will stretch to exactly match the viewport size -->
  <item android:drawable="@drawable/ic_launcher_foreground" android:gravity="center"/> <!-- will be centered in the viewport without stretching -->
</layer-list>

src/app/tabs/tabs.page.ts

export class TabsPage implements AfterViewInit {

  // ...

  public ngAfterViewInit(): void {
    // Do this in your app landing page
    // You may adjust the timing and wait for any promises or data required by your app,
    // so its fully ready before hiding the splash screen
    // I just added a 100ms delay to help the transition be smooth as it can be quite laggy when your app just finished being rendered
    setTimeout(() => {
      SplashScreen.hide({fadeOutDuration: 300});
    }, 100);
  }

}

所以我们的目标是不让这些图像被拉伸或变胖。保留 标准宽高比 图像中的图像。要解决此问题并使启动图像响应屏幕设备和宽高比的天文变化,您将必须操纵:

  • capacitor.config.json(离子项目)
  • app.component.ts(离子项目)
  • styles.xml(Android 项目)

#1 电容器配置 JSON(离子项目)

{
 ...

    "plugins": {
        "SplashScreen": {
            "launchAutoHide": false,
            "androidScaleType": "CENTER_CROP",
            "splashFullScreen": true,
            "splashImmersive": false,
            "backgroundColor": "#ffffff" // YOUR SPLASH SCREEN MAIN COLOR
        }
    }

...
}

#2 App 组件 TS(离子项目)

import { Plugins } from '@capacitor/core'
const { SplashScreen } = Plugins;
...

export class AppComponent implements OnInit {
    ...

    // DON'T USE SPLASHSCREEN SHOW METHOD ANYWHERE
    // SplashScreen.show(); 

    initializeApp() {
        this.platform.ready().then(async () => {
            SplashScreen.hide();
        });
    }
}

#3 Styles.xml(Android 项目)

<?xml version="1.0" encoding="utf-8"?>
<resources>
...

    <style name="AppTheme.NoActionBarLaunch" parent="AppTheme.NoActionBar">
        <item name="android:background">@drawable/splash</item>
        <item name="android:windowNoTitle">false</item>
        <item name="android:windowActionBar">false</item>
        <item name="android:windowFullscreen">false</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>
<resources>

就是这样!所有图像现在都保留了宽高比,并且它们将始终响应所有设备。

参考资料