diff --git a/splash-screen/README.md b/splash-screen/README.md
index 0a4020e0a..f1adbb17a 100644
--- a/splash-screen/README.md
+++ b/splash-screen/README.md
@@ -71,19 +71,21 @@ To set the color of the spinner use `spinnerColor`, values are either `#RRGGBB`
These config values are available:
-| Prop | Type | Description | Default | Since |
-| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- | ----- |
-| **`launchShowDuration`** | number
| How long to show the launch splash screen when autoHide is enabled (in ms) | 0
| 1.0.0 |
-| **`launchAutoHide`** | boolean
| Whether to auto hide the splash after launchShowDuration. | true
| 1.0.0 |
-| **`backgroundColor`** | string
| Color of the background of the Splash Screen in hex format, #RRGGBB or #RRGGBBAA. | | 1.0.0 |
-| **`androidSplashResourceName`** | string
| Name of the resource to be used as Splash Screen. Only available on Android. | splash
| 1.0.0 |
-| **`androidScaleType`** | 'CENTER' \| 'CENTER_CROP' \| 'CENTER_INSIDE' \| 'FIT_CENTER' \| 'FIT_END' \| 'FIT_START' \| 'FIT_XY' \| 'MATRIX'
| The [ImageView.ScaleType](https://developer.android.com/reference/android/widget/ImageView.ScaleType) used to scale the Splash Screen image. Only available on Android. | FIT_XY
| 1.0.0 |
-| **`showSpinner`** | boolean
| Show a loading spinner on the Splash Screen. | | 1.0.0 |
-| **`androidSpinnerStyle`** | 'horizontal' \| 'small' \| 'large' \| 'inverse' \| 'smallInverse' \| 'largeInverse'
| Style of the Android spinner. | large
| 1.0.0 |
-| **`iosSpinnerStyle`** | 'small' \| 'large'
| Style of the iOS spinner. Only available on iOS. | large
| 1.0.0 |
-| **`spinnerColor`** | string
| Color of the spinner in hex format, #RRGGBB or #RRGGBBAA. | | 1.0.0 |
-| **`splashFullScreen`** | boolean
| Hide the status bar on the Splash Screen. Only available on Android. | | 1.0.0 |
-| **`splashImmersive`** | boolean
| Hide the status bar and the software navigation buttons on the Splash Screen. Only available on Android. | | 1.0.0 |
+| Prop | Type | Description | Default | Since |
+| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | ----- |
+| **`launchShowDuration`** | number
| How long to show the launch splash screen when autoHide is enabled (in ms) | 0
| 1.0.0 |
+| **`launchAutoHide`** | boolean
| Whether to auto hide the splash after launchShowDuration. | true
| 1.0.0 |
+| **`backgroundColor`** | string
| Color of the background of the Splash Screen in hex format, #RRGGBB or #RRGGBBAA. Doesn't work if `useDialog` is true. | | 1.0.0 |
+| **`androidSplashResourceName`** | string
| Name of the resource to be used as Splash Screen. Only available on Android. | splash
| 1.0.0 |
+| **`androidScaleType`** | 'CENTER' \| 'CENTER_CROP' \| 'CENTER_INSIDE' \| 'FIT_CENTER' \| 'FIT_END' \| 'FIT_START' \| 'FIT_XY' \| 'MATRIX'
| The [ImageView.ScaleType](https://developer.android.com/reference/android/widget/ImageView.ScaleType) used to scale the Splash Screen image. Doesn't work if `useDialog` is true. Only available on Android. | FIT_XY
| 1.0.0 |
+| **`showSpinner`** | boolean
| Show a loading spinner on the Splash Screen. Doesn't work if `useDialog` is true. | | 1.0.0 |
+| **`androidSpinnerStyle`** | 'horizontal' \| 'small' \| 'large' \| 'inverse' \| 'smallInverse' \| 'largeInverse'
| Style of the Android spinner. Doesn't work if `useDialog` is true. | large
| 1.0.0 |
+| **`iosSpinnerStyle`** | 'small' \| 'large'
| Style of the iOS spinner. Doesn't work if `useDialog` is true. Only available on iOS. | large
| 1.0.0 |
+| **`spinnerColor`** | string
| Color of the spinner in hex format, #RRGGBB or #RRGGBBAA. Doesn't work if `useDialog` is true. | | 1.0.0 |
+| **`splashFullScreen`** | boolean
| Hide the status bar on the Splash Screen. Only available on Android. | | 1.0.0 |
+| **`splashImmersive`** | boolean
| Hide the status bar and the software navigation buttons on the Splash Screen. Only available on Android. | | 1.0.0 |
+| **`layoutName`** | string
| If `useDialog` is set to true, configure the Dialog layout. If `useDialog` is not set or false, use a layout instead of the ImageView. Only available on Android. | | 1.1.0 |
+| **`useDialog`** | boolean
| Use a Dialog instead of an ImageView. If `layoutName` is not configured, it will use a layout that uses the splash image as background. Only available on Android. | | 1.1.0 |
### Examples
@@ -103,7 +105,9 @@ In `capacitor.config.json`:
"iosSpinnerStyle": "small",
"spinnerColor": "#999999",
"splashFullScreen": true,
- "splashImmersive": true
+ "splashImmersive": true,
+ "layoutName": "launch_screen",
+ "useDialog": true
}
}
}
@@ -130,6 +134,8 @@ const config: CapacitorConfig = {
spinnerColor: "#999999",
splashFullScreen: true,
splashImmersive: true,
+ layoutName: "launch_screen",
+ useDialog: true,
},
},
};
diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java
index a745e8651..6ef6fac08 100644
--- a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java
+++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreen.java
@@ -1,6 +1,8 @@
package com.capacitorjs.plugins.splashscreen;
import android.animation.Animator;
+import android.app.Activity;
+import android.app.Dialog;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -9,11 +11,11 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Handler;
-import android.view.Gravity;
-import android.view.View;
-import android.view.WindowManager;
+import android.view.*;
import android.view.animation.LinearInterpolator;
+import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.ProgressBar;
import androidx.appcompat.app.AppCompatActivity;
import com.getcapacitor.Logger;
@@ -23,7 +25,8 @@
*/
public class SplashScreen {
- private ImageView splashImage;
+ private Dialog dialog;
+ private View splashImage;
private ProgressBar spinnerBar;
private WindowManager windowManager;
private boolean isVisible = false;
@@ -49,8 +52,11 @@ public void showOnLaunch(final AppCompatActivity activity) {
settings.setShowDuration(config.getLaunchShowDuration());
settings.setAutoHide(config.isLaunchAutoHide());
settings.setFadeInDuration(config.getLaunchFadeInDuration());
-
- show(activity, settings, null, true);
+ if (config.isUsingDialog()) {
+ showDialog(activity, settings, null, true);
+ } else {
+ show(activity, settings, null, true);
+ }
}
/**
@@ -61,7 +67,83 @@ public void showOnLaunch(final AppCompatActivity activity) {
* @param splashListener A listener to handle the finish of the animation (if any)
*/
public void show(final AppCompatActivity activity, final SplashScreenSettings settings, final SplashListener splashListener) {
- show(activity, settings, splashListener, false);
+ if (config.isUsingDialog()) {
+ showDialog(activity, settings, splashListener, false);
+ } else {
+ show(activity, settings, splashListener, false);
+ }
+ }
+
+ private void showDialog(
+ final AppCompatActivity activity,
+ final SplashScreenSettings settings,
+ final SplashListener splashListener,
+ final boolean isLaunchSplash
+ ) {
+ if (activity == null || activity.isFinishing()) return;
+
+ if (isVisible) {
+ splashListener.completed();
+ return;
+ }
+
+ activity.runOnUiThread(
+ () -> {
+ if (config.isImmersive()) {
+ dialog = new Dialog(activity, R.style.capacitor_immersive_style);
+ } else if (config.isFullScreen()) {
+ dialog = new Dialog(activity, R.style.capacitor_full_screen_style);
+ } else {
+ dialog = new Dialog(activity, R.style.capacitor_default_style);
+ }
+ int splashId = 0;
+ if (config.getLayoutName() != null) {
+ splashId = context.getResources().getIdentifier(config.getLayoutName(), "layout", context.getPackageName());
+ if (splashId == 0) {
+ Logger.warn("Layout not found, using default");
+ }
+ }
+ if (splashId != 0) {
+ dialog.setContentView(splashId);
+ } else {
+ Drawable splash = getSplashDrawable();
+ LinearLayout parent = new LinearLayout(context);
+ parent.setLayoutParams(
+ new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)
+ );
+ parent.setOrientation(LinearLayout.VERTICAL);
+ if (splash != null) {
+ parent.setBackground(splash);
+ }
+ dialog.setContentView(parent);
+ }
+
+ dialog.setCancelable(false);
+ if (!dialog.isShowing()) {
+ dialog.show();
+ }
+ isVisible = true;
+
+ if (settings.isAutoHide()) {
+ new Handler()
+ .postDelayed(
+ () -> {
+ hideDialog(activity, isLaunchSplash);
+
+ if (splashListener != null) {
+ splashListener.completed();
+ }
+ },
+ settings.getShowDuration()
+ );
+ } else {
+ // If no autoHide, call complete
+ if (splashListener != null) {
+ splashListener.completed();
+ }
+ }
+ }
+ );
}
/**
@@ -73,6 +155,15 @@ public void hide(SplashScreenSettings settings) {
hide(settings.getFadeOutDuration(), false);
}
+ /**
+ * Hide the Splash Screen when showing it as a dialog
+ *
+ * @param activity the activity showing the dialog
+ */
+ public void hideDialog(final AppCompatActivity activity) {
+ hideDialog(activity, false);
+ }
+
public void onPause() {
tearDown(true);
}
@@ -83,34 +174,53 @@ public void onDestroy() {
private void buildViews() {
if (splashImage == null) {
- int splashId = context.getResources().getIdentifier(config.getResourceName(), "drawable", context.getPackageName());
-
+ int splashId = 0;
Drawable splash;
- try {
- splash = context.getResources().getDrawable(splashId, context.getTheme());
- } catch (Resources.NotFoundException ex) {
- Logger.warn("No splash screen found, not displaying");
- return;
- }
- if (splash instanceof Animatable) {
- ((Animatable) splash).start();
+ if (config.getLayoutName() != null) {
+ splashId = context.getResources().getIdentifier(config.getLayoutName(), "layout", context.getPackageName());
+ if (splashId == 0) {
+ Logger.warn("Layout not found, defaulting to ImageView");
+ }
}
- if (splash instanceof LayerDrawable) {
- LayerDrawable layeredSplash = (LayerDrawable) splash;
+ if (splashId != 0) {
+ Activity activity = (Activity) context;
+ LayoutInflater inflator = activity.getLayoutInflater();
+ ViewGroup root = new FrameLayout(context);
+ root.setLayoutParams(
+ new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
+ );
+ splashImage = inflator.inflate(splashId, root, false);
+ } else {
+ splash = getSplashDrawable();
+ if (splash != null) {
+ if (splash instanceof Animatable) {
+ ((Animatable) splash).start();
+ }
+
+ if (splash instanceof LayerDrawable) {
+ LayerDrawable layeredSplash = (LayerDrawable) splash;
- for (int i = 0; i < layeredSplash.getNumberOfLayers(); i++) {
- Drawable layerDrawable = layeredSplash.getDrawable(i);
+ for (int i = 0; i < layeredSplash.getNumberOfLayers(); i++) {
+ Drawable layerDrawable = layeredSplash.getDrawable(i);
- if (layerDrawable instanceof Animatable) {
- ((Animatable) layerDrawable).start();
+ if (layerDrawable instanceof Animatable) {
+ ((Animatable) layerDrawable).start();
+ }
+ }
}
+
+ splashImage = new ImageView(context);
+ // Stops flickers dead in their tracks
+ // https://stackoverflow.com/a/21847579/32140
+ ImageView imageView = (ImageView) splashImage;
+ imageView.setDrawingCacheEnabled(true);
+ imageView.setScaleType(config.getScaleType());
+ imageView.setImageDrawable(splash);
}
}
- splashImage = new ImageView(context);
-
splashImage.setFitsSystemWindows(true);
if (config.isImmersive()) {
@@ -126,16 +236,9 @@ private void buildViews() {
splashImage.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN);
}
- // Stops flickers dead in their tracks
- // https://stackoverflow.com/a/21847579/32140
- splashImage.setDrawingCacheEnabled(true);
-
if (config.getBackgroundColor() != null) {
splashImage.setBackgroundColor(config.getBackgroundColor());
}
-
- splashImage.setScaleType(config.getScaleType());
- splashImage.setImageDrawable(splash);
}
if (spinnerBar == null) {
@@ -162,6 +265,17 @@ private void buildViews() {
}
}
+ private Drawable getSplashDrawable() {
+ int splashId = context.getResources().getIdentifier(config.getResourceName(), "drawable", context.getPackageName());
+ try {
+ Drawable drawable = context.getResources().getDrawable(splashId, context.getTheme());
+ return drawable;
+ } catch (Resources.NotFoundException ex) {
+ Logger.warn("No splash screen found, not displaying");
+ return null;
+ }
+ }
+
private void show(
final AppCompatActivity activity,
final SplashScreenSettings settings,
@@ -333,6 +447,36 @@ public void onAnimationRepeat(Animator animator) {}
);
}
+ private void hideDialog(final AppCompatActivity activity, boolean isLaunchSplash) {
+ // Warn the user if the splash was hidden automatically, which means they could be experiencing an app
+ // that feels slower than it actually is.
+ if (isLaunchSplash && isVisible) {
+ Logger.debug(
+ "SplashScreen was automatically hidden after the launch timeout. " +
+ "You should call `SplashScreen.hide()` as soon as your web app is loaded (or increase the timeout)." +
+ "Read more at https://capacitorjs.com/docs/apis/splash-screen#hiding-the-splash-screen"
+ );
+ }
+
+ if (isHiding) {
+ return;
+ }
+
+ isHiding = true;
+
+ activity.runOnUiThread(
+ () -> {
+ if (dialog != null && dialog.isShowing()) {
+ if (!activity.isFinishing() && !activity.isDestroyed()) {
+ dialog.dismiss();
+ }
+ dialog = null;
+ isVisible = false;
+ }
+ }
+ );
+ }
+
private void tearDown(boolean removeSpinner) {
if (spinnerBar != null && spinnerBar.getParent() != null) {
spinnerBar.setVisibility(View.INVISIBLE);
diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenConfig.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenConfig.java
index 642d611b5..043bbde2e 100644
--- a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenConfig.java
+++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenConfig.java
@@ -15,6 +15,8 @@ public class SplashScreenConfig {
private boolean immersive = false;
private boolean fullScreen = false;
private ScaleType scaleType = ScaleType.FIT_XY;
+ private boolean usingDialog = false;
+ private String layoutName;
public Integer getBackgroundColor() {
return backgroundColor;
@@ -99,4 +101,20 @@ public ScaleType getScaleType() {
public void setScaleType(ScaleType scaleType) {
this.scaleType = scaleType;
}
+
+ public boolean isUsingDialog() {
+ return usingDialog;
+ }
+
+ public void setUsingDialog(boolean usingDialog) {
+ this.usingDialog = usingDialog;
+ }
+
+ public String getLayoutName() {
+ return layoutName;
+ }
+
+ public void setLayoutName(String layoutName) {
+ this.layoutName = layoutName;
+ }
}
diff --git a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java
index 70c22ffdb..d4e06258e 100644
--- a/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java
+++ b/splash-screen/android/src/main/java/com/capacitorjs/plugins/splashscreen/SplashScreenPlugin.java
@@ -12,9 +12,10 @@
public class SplashScreenPlugin extends Plugin {
private SplashScreen splashScreen;
+ private SplashScreenConfig config;
public void load() {
- SplashScreenConfig config = getSplashScreenConfig();
+ config = getSplashScreenConfig();
splashScreen = new SplashScreen(getContext(), config);
splashScreen.showOnLaunch(getActivity());
}
@@ -40,7 +41,11 @@ public void error() {
@PluginMethod
public void hide(PluginCall call) {
- splashScreen.hide(getSettings(call));
+ if (config.isUsingDialog()) {
+ splashScreen.hideDialog(getActivity());
+ } else {
+ splashScreen.hide(getSettings(call));
+ }
call.resolve();
}
@@ -142,6 +147,13 @@ private SplashScreenConfig getSplashScreenConfig() {
Boolean showSpinner = getConfig().getBoolean("showSpinner", config.isShowSpinner());
config.setShowSpinner(showSpinner);
+ Boolean useDialog = getConfig().getBoolean("useDialog", config.isUsingDialog());
+ config.setUsingDialog(useDialog);
+
+ if (getConfig().getString("layoutName") != null) {
+ config.setLayoutName(getConfig().getString("layoutName"));
+ }
+
return config;
}
}
diff --git a/splash-screen/android/src/main/res/values/styles.xml b/splash-screen/android/src/main/res/values/styles.xml
new file mode 100644
index 000000000..3534cf911
--- /dev/null
+++ b/splash-screen/android/src/main/res/values/styles.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/splash-screen/src/definitions.ts b/splash-screen/src/definitions.ts
index bc91ef1e4..1f4256aad 100644
--- a/splash-screen/src/definitions.ts
+++ b/splash-screen/src/definitions.ts
@@ -26,6 +26,7 @@ declare module '@capacitor/cli' {
/**
* Color of the background of the Splash Screen in hex format, #RRGGBB or #RRGGBBAA.
+ * Doesn't work if `useDialog` is true.
*
* @since 1.0.0
* @example "#ffffffff"
@@ -46,6 +47,7 @@ declare module '@capacitor/cli' {
/**
* The [ImageView.ScaleType](https://developer.android.com/reference/android/widget/ImageView.ScaleType) used to scale
* the Splash Screen image.
+ * Doesn't work if `useDialog` is true.
*
* Only available on Android.
*
@@ -65,6 +67,7 @@ declare module '@capacitor/cli' {
/**
* Show a loading spinner on the Splash Screen.
+ * Doesn't work if `useDialog` is true.
*
* @since 1.0.0
* @example true
@@ -73,6 +76,7 @@ declare module '@capacitor/cli' {
/**
* Style of the Android spinner.
+ * Doesn't work if `useDialog` is true.
*
* @since 1.0.0
* @default large
@@ -88,6 +92,7 @@ declare module '@capacitor/cli' {
/**
* Style of the iOS spinner.
+ * Doesn't work if `useDialog` is true.
*
* Only available on iOS.
*
@@ -99,6 +104,7 @@ declare module '@capacitor/cli' {
/**
* Color of the spinner in hex format, #RRGGBB or #RRGGBBAA.
+ * Doesn't work if `useDialog` is true.
*
* @since 1.0.0
* @example "#999999"
@@ -124,6 +130,29 @@ declare module '@capacitor/cli' {
* @example true
*/
splashImmersive?: boolean;
+
+ /**
+ * If `useDialog` is set to true, configure the Dialog layout.
+ * If `useDialog` is not set or false, use a layout instead of the ImageView.
+ *
+ * Only available on Android.
+ *
+ * @since 1.1.0
+ * @example "launch_screen"
+ */
+ layoutName?: string;
+
+ /**
+ * Use a Dialog instead of an ImageView.
+ * If `layoutName` is not configured, it will use
+ * a layout that uses the splash image as background.
+ *
+ * Only available on Android.
+ *
+ * @since 1.1.0
+ * @example true
+ */
+ useDialog?: boolean;
};
}
}