On an app I'm working on, we have a splash screen consisting of a RelativeLayout and a logo in the center (and some other stuff, like a loading spinner, etc):
fragment_splash_image.xml:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:background="@drawable/loading_screen_bg"
... >
<ImageView
android:id="@+id/universal_loading_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/logo_large"
... />
... other stuff ...
</RelativeLayout>
To make sure there wasn't just a brief blank screen before our splash screen, we have a SplashTheme in styles.xml for the activity. Its android:windowBackground
is just a layer-list with the logo in the center again, with the hopes that the logo would appear to stay in the middle of the screen while the other things in fragment_splash_image appear as well.
splash_placeholder.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
<item android:drawable="@drawable/loading_screen_gradient"/>
<item>
<bitmap
android:gravity="center"
android:src="@drawable/logo_large"/>
</item>
</layer-list>
Notice that @drawable/logo_large
is the same logo in each, and centered on the screen in each. The intended behavior is that it shouldn't appear to move at all.
Anyway, fragment_splash_image
is inflated in a class that extends from FrameLayout, in this method:
private void inflateContent() {
final View splashImageFragment = LayoutInflater.from(getContext()).inflate(R.layout.fragment_splash_image, this, true);
final ImageView brandLogo = (ImageView) splashImageFragment.findViewById(R.id.universal_loading_logo);
final int statusBarHeight = ScreenUtils.getStatusBarHeight(getResources());
final int navBarHeight = !ScreenUtils.hasSoftNavBar() ? 0 : ScreenUtils.getNavigationBarHeight(getResources());
brandLogo.setPadding(0, 0, 0, statusBarHeight - navBarHeight);
}
Now, what's going on in there is that originally, we just inflated the fragment as-is. Unfortunately, this causes the logo in the splash fragment to jump up or down a small distance compared to the splash placeholder's logo, depending on the device tested on. On my Galaxy S6 phone, I figured that perhaps the placeholder splash screen included the status bar height, so I added it as padding to the bottom of the logo. Problem solved for that device. However, on a Nexus 7 which has a soft navigation bar, the logo still jumped very far up. I concluded that maybe it was also including the navbar height in the layout bounds, and wrote what you see above: bottom padding = statusBarHeight - navBarHeight, where navBarHeight is 0 for devices with hard navigation buttons.
This works for both devices...and then I tested on a Google Pixel. The logo jumps down. This only works on the Pixel if I set the bottom padding to 0, and the top padding to the status bar height.
I'm stumped. What the heck is determining the height of both layouts here? They are clearly different and I'm not sure how to ensure that the logo does not jump from one screen to the next on any devices. Thanks in advance!
Adding <item name="android:windowDrawsSystemBarBackgrounds">false</item>
on API 21+ may allow you to keep the same formula for all devices.
I am facing a similar issue, and thinking about going this route.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With