If you are using the #capacitor/splash-screen API to show a splash screen in your Ionic Android app with Capacitor 3 you might run into this issue:
Problem
For a fraction of a second the splash image will be shown distorted until it is shown in the correct aspect ratio. That means that it also "jumps" a bit on the screen This will especially be noticeable if you launch the app while the device is in landscape orientation or if you your device has stretched or fat display aspect ratio.
Background Info
It happens because AppTheme.NoActionBarLaunch that is used on app launch for MainActivity is set up to have the splash image as the background image, but the "real" splash image is initialized a couple of milliseconds later in the SplasScreen.buildViews() method of the plugin.
Solution
To fix it, you can change the following in your styles.xml file under /android/app/src/main/values:
Old:
<style name="AppTheme.NoActionBarLaunch" parent="AppTheme.NoActionBar">
<item name="android:background">#drawable/splash</item>
</style>
New (no background):
<style name="AppTheme.NoActionBarLaunch" parent="AppTheme.NoActionBar">
<item name="android:background">#null</item>
</style>
Or set the background color of your splash screen:
<style name="AppTheme.NoActionBarLaunch" parent="AppTheme.NoActionBar">
<item name="android:background">#ffffff</item>
</style>
This will prevent the showing of the splash image as a background image before the actual ImageView is added to the view hierarchy. The ImageView will have the correct scaleType as defined in androidScaleType of the plugin configuration.
Tested with the following versions:
#capacitor/android: 3.0.0-rc.0
#capacitor/splash-screen: 0.3.6
#ionic/angular: 5.6.3
The following configuration is used:
const config: CapacitorConfig = {
// ...
plugins: {
SplashScreen: {
launchShowDuration: 3000,
launchAutoHide: false,
backgroundColor: '#ffffffff',
androidSplashResourceName: 'splash',
androidScaleType: 'CENTER_CROP',
showSpinner: false,
splashFullScreen: false,
splashImmersive: false,
},
},
// ...
};
Note: No need to call SplashScreen.show() in the TypeScript (Ionic) code, it will automatically be shown. Just call SplashScreen.hide() in your TypeScript code once you want to hide the SplashScreen.
The above workaround does not work with the community barcode scanner which require transparent background.
My workaround (the drawback with blank white screen still exist there but it work):
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowActionBar">false</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">#android:color/white</item>
</style>
<style name="AppTheme.NoActionBarLaunch" parent="AppTheme.NoActionBar"></style>
Related
Context
This is related to the splash screen images responsiveness and according to my research it just happens because there is missing documentation at Capacitor Docs - Splash Screen.
Problem
The problem starts when implementing the splash screen plugin of capacitor. Normally this implementation is made from scratch when you create the whole project. However it doesn't/didn't worked well on devices that have a stretched aspect ratio (for example Google Pixel 2 XL) or devices that have fat aspect ratio (for example iPad Pro). There are even some scenarios in which the splash screen image moves around or shrinks/expands (while loading).
Visual Explanation
In other words the native implementation is causing the splash screen images to be just like in the image below. If the devices are stretched or fat the images aspect ratio aren't preserved.
So the goal is to not make this images to be stretched or fattened. To preserve the image like in the standard aspect ratio image. To solve this issue and make the splash images become responsive to the astronomic variety of a screen devices and aspect ratios you will have to manipulate:
capacitor.config.json (Ionic Project)
app.component.ts (Ionic Project)
styles.xml (Android Project)
#1 Capacitor Config JSON (Ionic Project)
{
...
"plugins": {
"SplashScreen": {
"launchAutoHide": false,
"androidScaleType": "CENTER_CROP",
"splashFullScreen": true,
"splashImmersive": false,
"backgroundColor": "#ffffff" // YOUR SPLASH SCREEN MAIN COLOR
}
}
...
}
#2 App Component TS (Ionic Project)
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 Project)
<?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>
And that's it! All the images are now with the aspect ratio preserved and they will always be responsive for all devices.
References
https://capacitorjs.com/docs/apis/splash-screen
https://github.com/ionic-team/capacitor/issues/1627#issuecomment-650835957
https://github.com/ionic-team/capacitor/issues/1627#issuecomment-707188787
if you getting splash screen two times (Blinking) try this in 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>
Solutions suggested in other posts may work for you if you use a plain color as the background of your splash screen, but if you use a complex image (like a gradient), here is what you need to know:
If you want a seamless transition between your splashscreen and your app, you need to install #capacitor/splash-screen as the Android <item name="android:background">#drawable/splash</item> will not allow you to fade out the splash screen, furthermore when the Android splash screen is replaced by your Ionic App, you will experience a brief empty screen while the WebView is rendered.
The #capacitor/splash-screen allows you to mitigate this by choosing yourself when the splash-screen should be hidden and how long the fade out should take.
#capacitor/splash-screen does NOT replace the native Android splash screen <item name="android:background">#drawable/splash</item>, instead it create an Android ImageView as soon as the Ionic App is open (after the native Splash Screen) and then fades out to the WebView.
You could hide the native Android splash screen to just use the #capacitor/splash-screen one by setting <item name="android:background">#null</item> for the native splash screen, but this is considered as a bad practice as it will give the illusion of hanging out for a few moment each time you launch your app (the time required for the Ionic App to be created and displayed on screen).
Finally, if you want the native Android splash screen to cover the entire screen and keep its aspect ratio, this is simply not possible (at least with Android 11 and earlier), you can only do this with an ImageView after the app as already booted.
So... Here is what you can do to mitigate this :
First, make sure the config for the native Android splash screen and the splash screen created by #capacitor/splash-screen are the same, so you don't get a "resize" when it goes from the first one to the second one.
Then, you'll have to split you splash screen in 2 layers, one for the background (that can be stretched to fill the viewport without keeping its aspect ratio), and one for your logo (or other element that sould be centered and keep its aspect ratio).
Then, create a custom drawable for your splash screen (i.e. drawable/launch_splash.xml), that will allow you to create a splash screen with as many layers as you want (in our case 2, one for the background, one for the logo).
And finally, use this custom drawable in place of the original splash screen.
Here is a full example of what I did:
capacitor.config.ts
const config: CapacitorConfig = {
// ...
plugins: {
// ...
SplashScreen: {
launchAutoHide: false,
androidSplashResourceName: 'launch_splash',
},
},
};
(Make sure you rebuild your app after you make any changes to the capacitor.config.ts or report the changes yourself to the capacitor.config.json file).
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);
}
}
When I upgraded my app from Capacitor v3 to Capacitor v4 on Android devices the splashscreen got distorted again.
What I had to do was creating 9-patch-png files in the drawable-folders (where the image for the splash screen is) instead of the regular png files.
I followed this guide on how to create those files: https://www.joshmorony.com/creating-a-dynamic-universal-splash-screen-for-capacitor-android/
I support Dominik's answer. You just need to create 9-patch-png files and delete your current PNG files.
I used this as reference
https://www.joshmorony.com/creating-a-dynamic-universal-splash-screen-for-capacitor-android/
The last part is outdated. You don't need to edit anything else. Just make sure you're using #drawable/splash in your styles.xml.
To easily set the stretchable areas, tick the Show patches box then use the top and left areas outside your image to drag and set the areas to your liking. You should be able to see green and pink areas around your logo but no overlay color on your actual logo.
The top and left areas is used to set the stretchable areas while the bottom and right areas is to set where the content should be contained. You just want to aim for the top and left black borders for this use case.
Background: My background is in web development, ruby and javascript. I'm working on a mostly react-native app, so very likely I'm missing something basic.
What I want
android navigation bar to be white with dark system buttons see image in link white navigation bar
My Current Code
res/values/style.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowLightNavigationBar">true</item>
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:navigationBarColor">#FFFFFF</item>
</style>
</resources>
What is happening instead
The background AND the buttons are white. which is not so great for UX.
** What I have Tried **
this is what got me where I am now Change navigation bar icon color on Android
I have tried putting style.xml in a values-v27 folder.
I just worked on this same topic and found out you need to run at least Android 9.0 (or API level 28) on the device/emulator for this to work.
Also, I had to add this to the color of the bar:
<item name="android:navigationBarColor">#android:color/white</item>
So, recommended steps:
Create a values-v28 folder
Insert the style:
<item name="android:navigationBarColor">#android:color/white</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowLightNavigationBar">true</item>
In your other values folder, you kind of have to live with the fact that this windowsLightNavigationBar doesn't apply...
Small remark
I also found a bug on this change, when putting app in background and then opening it again, the navbar buttons stay white for a second before getting the dark color
Your code is working as intended for me. Make sure you have the file name and file path written correctly:
https://imgur.com/xclYDuZ
A new approach would be:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.navigationBarColor = ContextCompat.getColor(this, android.R.color.white)
WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightNavigationBars = true
}
I have noticed that on android versions 6.0+,when someone starting app after login screen and submiting info,black screen appear and you have to wait 3-15 sec depending on devices.
I heard that it could be for heavy loadings,but this app is nothing special it just load listview with few images after login (i had 3 images while tested) so im not sure is it really that heavy plus it only happen on newer versions of android so im not sure what to do.
I can provide whole code or some snippet.
EDIT: I tried with various image sizes (full loaded with big images,and only 1 small image) and it have no effect at all.
Anyone???
Inside your manifest file .
In your Activity tag add this theme.
android:theme="#android:style/Theme.Translucent"
And then you need to extend your respective activity from Activity class.
It will work for sure
For those who face this error in future
<style name="FullscreenTheme" parent="MainTheme">
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="android:windowFullscreen">true</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:windowIsTranslucent">true</item>
</style>
I have added a custom theme with background image to serve as "splash" image to make the app look nicer while unity player is loading.
That's the theme definition I have
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Test" parent="#android:style/Theme.Light.NoTitleBar.Fullscreen">
<item name="android:windowBackground">#drawable/launchimage</item>
<item name="android:windowContentOverlay">#null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
</resources>
Now, when I refer to this theme in AndroidManifest.xml like:
<activity android:name="com.unity3d.player.UnityPlayerActivity" android:theme="#style/Theme.Test" ... ></activity>
the game just "freezes" – it's hard to tell in fact, because it just displays the splash image and ... that's it. Logcat doesn't show any warnings/errors either.
Removing the theme OR changing android:windowBackground property to a solid color make the game work, but window background appears black until the game is launched.
What is the correct way to set activity background to make Unity happy?
When your image is too large this issue happen. change your image with smaller and set centerCrop attribute may fixed this issue. (usually this show skip frame in your log)
Also if you use Android studio 2.0 there is newly issue with that you can find it here.
Currently, I'm using this to show my application background as phone wallpaper.
getWindow().setFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER,
WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
But for some reason when I start my application by pressing the icon. It just shows the activity screen with the icons on the home screen. I didn't use dialog but it looks like a dialog because layout is just set that way. So I just want to show the wallpaper whenever this activity is running. But it only shows the wallpaper only after the next event occurs such as switching to different activity. I already put that code on onCreate() and whenever I do setContentView()..... Is there way to do such thing or there is just no way?
For users of AppCompat, just use the following in your styles.xml, no need for code:
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat">
<item name="android:windowBackground">#android:color/transparent</item>
<item name="android:colorBackgroundCacheHint">#null</item>
<item name="android:windowShowWallpaper">true</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
After long search and trial and error. I've found the solution to what I wanted. It was just creating separate themes.xml file and just tweak the Theme.Dialog which is already defined in default android themes.xml. All I did was change the Animation part. Originally in android themes.xml the line looks like this.
<item name="android:windowAnimationStyle">#android:style/Animation.Dialog</item>
but since modifying in android themes.xml doesn't take the effect. I just created my own themes.xml as I said above and just set parent as android:Theme.Dialog. And added a line like this.
<item name="android:windowAnimationStyle">#android:style/Animation</item>
Thanks for the help and I hope this solution helps others.
Use following code -
rl = (RelativeLayout)findViewById(R.id.someid);
//relative layout is my root node in main.xml (yours may be linearlayout)
WallpaperManager wm = WallpaperManager.getInstance(this);
Drawable d = wm.peekDrawable();
rl.setBackgroundDrawable(d);// You can also use rl.setBackgroundDrawable(getWallpaper);