离子和电容器 - 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>
就是这样!所有图像现在都保留了宽高比,并且它们将始终响应所有设备。
参考资料
上下文
这与启动画面图像的响应有关,根据我的研究,这只是因为 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>
就是这样!所有图像现在都保留了宽高比,并且它们将始终响应所有设备。