Android splash screen without logo distortion
Asked Answered
P

6

7

Is it possible to create a splash screen with a logo that maintains its aspect ratio while the background image can be resized independently? I'm currently using several .png files for different resolutions and they look great on most devices. However, there are a few phones that distort my logo severely (i.e. the Samsung S8, with move vertical screen space).

I can deal with some distortion for my splash screen background, but the skinny/squashed logo is unacceptable. Does anyone know how to do this? And would a vector drawable logo be better than a .png for the new layout?

Pyromancy answered 28/7, 2017 at 17:21 Comment(4)
is your image (imageview) have wrap_content for weight and height?Beaulieu
No, it's match_parent.Pyromancy
If I understand, you have a background image, and then an image over it. and the image (your icon) is distorting on some devices?Beaulieu
i posted an answerBeaulieu
L
3

If you only have a portrait image for your splash screen, here's a solution which is full screen on portrait, and centred but not cropped on edit: portrait landscape:

splash_screen.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layoutSplash"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/splash_screen_background">

    <ImageView
        android:contentDescription="@string/splash_screen_description"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        style="@style/SplashScreen" />

</LinearLayout>

values/styles.xml

<style name="SplashScreen">
    <item name="android:src">@drawable/splash</item>
    <item name="android:adjustViewBounds">true</item>
    <item name="android:scaleType">fitCenter</item>
</style>

values-port/styles.xml

<style name="SplashScreen">
    <item name="android:src">@drawable/splash</item>
    <item name="android:adjustViewBounds">true</item>
    <item name="android:scaleType">centerCrop</item>
</style>
Legendre answered 28/7, 2017 at 18:7 Comment(4)
How do you achieve this with a splashscreen before an activity has been created/started? You can't use a layout file. For logos I would set <item name="android:windowBackground">@drawable/splashscreen</item> at the theme.Paleoecology
I've only created splashscreens using activities. That could be a new StackOverflow question.Legendre
you should use windowBackground for splash screen.. with your solution you can still see white screen before your activity layout is inflated. bignerdranch.com/blog/splash-screens-the-right-way/…Hornbeam
Was able to get complete cover of image on screen by setting scaleType as centerCrop . Thanks!Lignite
L
19

Rendering a splash view in a layout.xml instead of as a theme background (like other answers here recommend) takes longer to load. This is because the app's theme is loaded first, then the Activity is constructed and the layout inflated last. Since the purpose of a splash screen is to display something while the app loads, having a ~0.5s delay in loading the splash screen itself results in a noticeable delay. Loading a splash as a theme windowBackground performs better (renders almost instantly after tapping the launcher icon), but has some restrictions to work around. Your current method of defining multiple logo sizes depending on the screen width is the correct way to handle this situation. Here is an example configuration, which handles differences between pre and post Android v21:

values/themes.xml:

<style name="SplashThemeCommon" parent="Theme.AppCompat.NoActionBar">
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowBackground">@drawable/splash_logo_theme</item>
</style>

<style name="SplashTheme" parent="SplashThemeCommon">
    <item name="android:windowFullscreen">true</item>
</style>

values-v21/themes.xml:

<style name="SplashTheme" parent="SplashThemeCommon">
    <item name="android:windowTranslucentStatus">true</item>
    <item name="android:windowTranslucentNavigation">true</item>
</style>

drawable/splash_logo_theme.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <bitmap
            android:gravity="center"
            android:src="@drawable/splash_logo"/>
    </item>
</layer-list>

Next you can include a copy of "splash_logo.png" for different screen configurations. You have a couple reasonable options here. An exhaustive approach might include different logos for each screen size:

  • drawable-sw320dp-xxxhdpi/splash_logo.png
  • drawable-sw400dp-xxxhdpi/splash_logo.png
  • drawable-sw480dp-xxxhdpi/splash_logo.png
  • drawable-sw600dp-xxxhdpi/splash_logo.png
  • drawable-sw720dp-xxxhdpi/splash_logo.png
  • drawable-sw820dp-xxxhdpi/splash_logo.png

The "swXXXdp" means that XXX is the smallest screen dimension (width or height) in dp. 820dp is going to be a huge tablet, 320dp will be an old small device, and most flagship devices today will be in the 400dp category. A 450dp wide device would use the 400dp image.

Why did I define xxxhdpi here? Because if you don't specify, Android will assume it is an mdpi image and try to upscale/resize for higher dpi devices (most flagship phones today are xxhdpi). This upscaling will result in your image being blocky, and larger than the original. By specifying xxxhdpi here, Android will only try to downscale the image ensuring that the image never goes blocky; this is a optimization so we don't also need to define separate images for ldpi, mdpi, hdpi, xhdpi etc.

Having 6 images in the APK is kind of a waste though. We can futher optimize this approach in order to include less images in the app and ensure a smaller APK size. Instead, let's include only the following two images:

  • drawable-sw600dp-xxxhdpi/splash_logo.png
  • drawable-xxxhdpi/splash_logo.png

Any devices 600dp and larger (tablets) have a larger copy of the image to take advantage of the larger screen real estate, while all other phones use a smaller copy located in the bin with no screen width qualifier. The drawback here is since each bin covers such a large range of screen widths, the logo on a 4" device will take up a larger portion of the screen than on a 6" devices. This is a compromise to cut down the APK size, and most users won't notice so long as the image never gets cut off even on the smallest device.

So what size png's should we include? They need to be a particular size to be displayed in a theme, since unlike in a layout.xml we cannot specify a width/height in the XML (drawable width/height support was only added in API 23). This means if you include a non-optimal png size, it will appear too small or two big; if its too big it will actually get cut off. A good plan to get the right size is:

  • Create an layout/test.xml file with just the default LinearLayout and no visible content
  • Open it in Android Studio and select the Design tab in the layout editor's bottom left corner
  • Change the theme to SplashTheme in the layout editor's top bar
  • Change the device to "Pixel XL"
  • Place an image under drawable-sw400dp/splash_logo.png
  • Open the image in an external image editor such as Photoshop or Gimp, change the size, save, then check the layout in Android Studio (you may need to close and reopen the editor for the change to take effect). Repeat until the image looks the correct size in the layout
  • Generate images for the other screen widths proportionately; for example the sw320dp image should be 320/400 or 67% of the 400dp image size, while the 720dp image should be 720/400 or 180% of the 400dp image size. Remember not to upscale your 400dp image for the larger images as you will lose quality. Instead, generate all the images based on your high quality original copy
  • Place the generated images in the different drawable directories as specified above
  • Select devices of different screen sizes (including tablets) in the layout editor and make sure they logo is large enough, but not cut off, for all screen sizes

How do you know which device screen resolution belongs to which swXXXdp category? This requires a simple calculation. Lets look at the Pixel XL:

  • The screen size is 1440x2560
  • The smallest dimension is therefore 1440
  • The screen dpi is 534
  • The screen width in inches is 1440/534=2.69"
  • Open the website: http://angrytools.com/android/pixelcalc/
  • Enter 2.69 in the inches ("in") box
  • One of the green boxes on the left will display the dp, in this case 431
  • With a 431 dp wide screen, the Pixel XL will use the drawable-sw400dp/splash_logo.png image if you have all 6 image categories, or the drawable-xxxhdpi/splash_logo.png image if you only have the two image categories
Lakeshialakey answered 26/9, 2017 at 21:35 Comment(3)
Nice explanation. ThanksMaritamaritain
Is there a template to what image sizes need to be put in each folderIndwell
2021 this does not work anymore. Android Drawable folder structure has changedIndwell
L
3

If you only have a portrait image for your splash screen, here's a solution which is full screen on portrait, and centred but not cropped on edit: portrait landscape:

splash_screen.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layoutSplash"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="@color/splash_screen_background">

    <ImageView
        android:contentDescription="@string/splash_screen_description"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        style="@style/SplashScreen" />

</LinearLayout>

values/styles.xml

<style name="SplashScreen">
    <item name="android:src">@drawable/splash</item>
    <item name="android:adjustViewBounds">true</item>
    <item name="android:scaleType">fitCenter</item>
</style>

values-port/styles.xml

<style name="SplashScreen">
    <item name="android:src">@drawable/splash</item>
    <item name="android:adjustViewBounds">true</item>
    <item name="android:scaleType">centerCrop</item>
</style>
Legendre answered 28/7, 2017 at 18:7 Comment(4)
How do you achieve this with a splashscreen before an activity has been created/started? You can't use a layout file. For logos I would set <item name="android:windowBackground">@drawable/splashscreen</item> at the theme.Paleoecology
I've only created splashscreens using activities. That could be a new StackOverflow question.Legendre
you should use windowBackground for splash screen.. with your solution you can still see white screen before your activity layout is inflated. bignerdranch.com/blog/splash-screens-the-right-way/…Hornbeam
Was able to get complete cover of image on screen by setting scaleType as centerCrop . Thanks!Lignite
R
0

Have you looked into maintaining the aspect ratio for the ImageView? Here is a relevant question that should point you in the right direction: How to scale an Image in ImageView to keep the aspect ratio

Runkle answered 28/7, 2017 at 17:26 Comment(0)
B
-1
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg"
    android:gravity="center">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/logo"/>

</RelativeLayout>

This will do this

enter image description here
This is on a nexus 10

enter image description here

Beaulieu answered 28/7, 2017 at 17:39 Comment(2)
you should use windowBackground for splash screen.. with your solution you can still see white screen before your activity layout is inflated. bignerdranch.com/blog/splash-screens-the-right-way/…Hornbeam
@Hornbeam windowBackground is extremely stupid and I spend tens of hours how to solve how to preserve aspect ratio of image = it is not possibleSpecify
B
-3

No need to use layouts at all, use a LayeredList, and set it as the background. Here is an example;

<?xml version="1.0" encoding="utf-8"?> 
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item android:drawable="@color/gray"/> 
    <item> 
        <bitmap android:gravity="center" android:src="@drawable/splash_image"/> 
    </item> 
</layer-list>
Bemis answered 31/7, 2017 at 4:51 Comment(5)
with gravity center image doesnt fit the screenTillfourd
Splash screens have no reason to fill screen.Bemis
I mean the image is too big, it's out of boundsTillfourd
@Tillfourd So add a lower resolution version of your image. This is something you should be doing in any case.Bemis
yes, sure, I just want to know what to say to designerTillfourd
I
-4
  1. In Android resources/res folder, create a folder "drawable-xxxhdpi" and "drawable-sw600dp"

  2. In "drawable-sw600dp" folder, add 'splash_logo.png' with resolution 4096x4096 pixels. This should cover tablets.

  3. In "drawable-xxxhdpi" folder, add another 'splash_logo.png" with resolution 1440x2560 pixels. This should cover smart phones.

That's how to solve all distortions!

Indwell answered 22/10, 2021 at 3:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.