I did my splash screen with this tutorial and it works great:
https://www.bignerdranch.com/blog/splash-screens-the-right-way/
Basically I set up a splascreen through theme:
<style name="ThemeSplash" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">#drawable/drawable_splashcreen</item>
</style>
I wanted to put a vector image inside like this: (drawable_splashcreen)
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/color_background_splash_screen" />
<item android:drawable="#drawable/vector_najdiflet_logo" />
</layer-list>
The image will streched through the full screen. On API 23 it works like it should have. But on older devices it just streches. I tried width, height and even messed up with viewports but no success.
I stumbled upon the same problem.
Unfortunately there does not seem to be a possibility to make the splash screen work with just a vector drawable for pre API 23.
The problem is you can't load VectorDrawableCompat outside of the process, like in this case in your themes android:windowBackground. So what is likely happening here is, that on API 21 the Vector get's converted to a PNG to be compatible. So in the <layered-list>the converted PNG is inserted into the <item> element, which causes the bitmap to stretch to all edges, because it's missing the <bitmap> element.
So my solution is the following: Create a drawable_splashscreen.xml inside the folder drawables-v23 which looks like the following for the vector drawable.
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:opacity="opaque">
<item android:drawable="?attr/colorPrimary"/>
<item android:drawable="#drawable/ic_splashscreen" android:gravity="center"/>
</layer-list>
Then create another drawable_splashscreen.xml but inside the regular drawables folder:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
android:opacity="opaque">
<item android:drawable="?attr/colorPrimary"/>
<item>
<bitmap android:src="#drawable/ic_splashscreen" android:gravity="center"/>
</item>
</layer-list>
Notice the <bitmap> element. So now, when the PNG is used on pre API 23 devices it will be displayed properly and won't be stretched to the whole background.
Unfortunately you also have to provide splash screen as PNG for this to work in the old APIs.
But for every device with API 23+ the vector drawable will be used.
For full screen splash try to use:
android:gravity="fill_horizontal|fill_vertical"
If not resolve maybe the solution is create separated images
for each resolution size.
Most common resolutions:
Small = 240 x 320px (ldpi)
Medium = 320 x 480px (mdpi)
Large = 480 x 800px (hdpi)
xLarge = 640 x 960px (xhdpi)
Portrait Format:
ldpi = 240 x 360px (0.75 x mdpi)
mdpi = 320 x 480px (base density)
hdpi = 480 x 720px (1.5 x mdpi)
xhdpi = 640 x 960px (2 x mdpi)
xxhdpi = 960 x 1440px (3 x mdpi)
xxxhdpi = 1080 x 1920px (4 x mdpi)
Landscape Format (inverted portrait format):
ldpi = 360 x 240px (0.75 x mdpi)
mdpi = 480 x 320px (base density)
hdpi = 720 x 480px (1.5 x mdpi)
xhdpi = 960 x 640px (2 x mdpi)
xxhdpi = 1440 x 960px (3 x mdpi)
xxxhdpi = 1920 x 1080px (4 x mdpi)
More about you can find here:
https://design.google.com/devices/
Android splash screen image sizes to fit all devices
http://vinsol.com/blog/2014/11/20/tips-for-designers-from-a-developer/
Edited solution that will make your SplashScreen look great on all APIs including API21 to API23
First of all read this article and follow the GOOD way of making a splash screen.
If your logo is distorted or wont fit and you are only targeting APIs24+ you can simply scale down your vector drawable directly in its xml file like so:
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
android:viewportWidth="640"
android:viewportHeight="640"
android:width="240dp"
android:height="240dp">
<path
android:pathData="M320.96 55.9L477.14 345L161.67 345L320.96 55.9Z"
android:strokeColor="#292929"
android:strokeWidth="24" />
</vector>
in the code above I am rescaling a drawable I drew on a 640x640 canvas to be 240x240. then i just put it in my splash screen drawable like so and it works great:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque"
android:paddingBottom="20dp" android:paddingRight="20dp" android:paddingLeft="20dp" android:paddingTop="20dp">
<!-- The background color, preferably the same as your normal theme -->
<item>
<shape>
<size android:height="120dp" android:width="120dp"/>
<solid android:color="#android:color/white"/>
</shape>
</item>
<!-- Your product logo - 144dp color version of your app icon -->
<item
android:drawable="#drawable/logo_vect"
android:gravity="center">
</item>
</layer-list>
my code is actually only drawing the triangle in the picture at the bottom but here you see what you can achieve with this. Resolution is finally great as opposed to the pixelated edges I was getting when using bitmap. so use a vector drawable by all means (there is a site called vectr that I used to create mine without the hasle of downloading specialized software).
EDIT in order to make it work also on API21-22-23
While the solution above works for devices runing API24+ I got really disappointed after installing my app a device running API22. I noticed that the splashscreen was again trying to fill the entire view and looking like shit. After tearing my eyebrows out for half a day I finally brute-forced a solution by sheer willpower.
you need to create a second file named exactly like the splashscreen xml (lets say splash_screen.xml) and place it into 2 folders called drawable-v22 and drawable-v21 that you will create in the res/ folder (in order to see them you have to change your project view from Android to Project). This serves to tell your phone to redirect to files placed in those folders whenever the relevant device runs an API corresponding to the -vXX suffix in the drawable folder, see this link. place the following code in the Layer-list of the splash_screen.xml file that you create in these folders:
<item>
<shape>
<size android:height="120dp" android:width="120dp"/>
<solid android:color="#android:color/white"/>
</shape>
</item>
<!-- Your product logo - 144dp color version of your app icon -->
<item android:gravity="center">
<bitmap android:gravity="center"
android:src="logo_vect"/>
</item>
For some reason for these APIs you have to wrap your drawable in a bitmap in order to make it work and jet the final result looks the same. The issue is that you have to use the aproach with the aditional drawable folders as the second version of the splash_screen.xml file will lead to your splash screen not being shown at all on devices running APIs higher than 23. You might also have to place the first version of the splash_screen.xml into drawable-v24 as android defaults to the closest drawable-vXX folder it can find for resources.
I do not think this is possible to do with vectors, for devices < API 23, since it is not possible to set the attributes android:height and android:width on the drawable.
To implement my splash screen with a centered icon, I had to export the vector of my logo to .png's for each screen size, and embed a bitmap within the layer-list:
<?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/splash_screen_background" />
<item
android:left="20dp"
android:right="20dp">
<bitmap
android:gravity="center"
android:scaleType="centerInside"
android:src="#drawable/logo_rasterised" />
</item>
</layer-list>
Ideally I would not like to have any bitmap images at all in my resources, but at least the splash screen is the only place where I have had to use bitmaps.
Use bitmap and define you image in the src. Set gravity to center
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:opacity="opaque">
<item android:drawable="#color/color_background_splash_screen"/>
<item>
<bitmap
android:gravity="center"
android:src="#drawable/ic_logo_splash"/>
</item>
</layer-list>
The simplest method I found to solve this is by using a vector asset.
This will ensure that the apk size is not big too. If you're not doing this or don't have an svg file for your logo, you should manually change the DP intensities of pictures and add them manually. You may also use plugins that do that automatically for you.
In case you go with the vector file and still end up getting a zoomed image, add in android:top, left right and bottom to get your logo size right.
Dont put your image in window:Background, instead add as android:src for an imageview for the layout of the SplashScreenActivity.
Related
I'm trying to make a splash screen for my app. This is my splash drawable:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="#color/colorRed"/>
<item>
<bitmap
android:gravity="center|fill"
android:src="#drawable/logoimage"/>
</item>
</layer-list>
But logoimage is always cropped and disturbed. It doesnt look good. I want to make it like fitCenter option of ImageView scaletype.
How can I do that?
The important thing here is your image.
Ensure you have alternative images for screens of varying pixel densities (mdpi, hdpi, xhdpi, xxhdpi and xxxhdpi). You can read about providing alternative image resources here
Depending on how big/small you want your logo in the splash you will need to have sizes for the images accordingly.
Note: You do not need the fill attribute for gravity. center attribute will do the job
I have a simple splash screen with a white background and the logo on the center of the screen. In a modern version of the Android, its work well but in 'old' versions of Android(for example API 22) my a logo is stretched on the full screen. How to make the logo splash screen look normal on all the version of Android (before API 19)?
p.s. I`m not the Android developer.
drawable/background_splash.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/white" />
<item
android:width="150dp"
android:height="50dp"
android:drawable="#mipmap/my_logo"
android:gravity="center" />
</layer-list>
values/styles.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:statusBarColor">#color/white</item>
</style>
<style name="SplashTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">#drawable/background_splash</item>
<item name="android:statusBarColor">#color/white</item>
</style>
</resources>
Instead of using a simple <item/> tag, use a <bitmap/> tag inside of an <item>.
From the Layer List drawable documentation:
All drawable items are scaled to fit the size of the containing View, by default. [...] To avoid scaling items in the list, use a <bitmap> element inside the <item> element to specify the drawable and define the gravity to something that does not scale, such as "center".
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#color/white" />
<item>
<bitmap
android:src="#mipmap/my_logo"
android:gravity="center"/>
</item>
</layer-list>
This is because the attributes android:width and android:height were introduced in API level 23. The only solution I can think of if you want to show the same image with a relative size according to the screen size is to provide alternative bitmap resources.
Here is a link to the Android Developer Guide which explains this a bit further.
First thing doesn't use a png use a vector drawable. This way you don't need a separate image for different screen size. Use this to convert image http://a-student.github.io/SvgToVectorDrawableConverter.Web/
and now in your image view in XML file set your scale type to Center Crop or Fit XY
android:scaleType="centerCrop" or use android:scaleType="fitxy"
The issue is not related to Android version. it should be related to the screen size of Devices.
To declare different layouts and bitmaps you'd like to use for the different screens, you must place these alternative resources in separate directories/folders.
This means that if you generate a 200x200 image for xhdpi devices, you should generate the same resource in 150x150 for hdpi, 100x100 for mdpi, and 75x75 for ldpi devices.
In a word, Android apps should provide 6 image sizes: ldpi (0.75x), mdpi (1.0x), hdpi (1.5x), xhdpi (2.0x), xxhdpi (3.0x), and xxxhdpi (4.0x).
What I usually do is I make sure my layout's root node is a RelativeLayout, and the first child is an ImageView with centerCrop as the scaleType.
Here's an example:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:scaleType="centerCrop"
android:background="#drawable/img_background"/>
...
Is it possible to get correctly scaled item drawable in android layer-list item?
I prepared something like this:
bg.xml:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="#drawable/splash_bg" />
<item
android:gravity="center"
android:drawable="#drawable/logo_white">
</item>
</layer-list>
The sizes for drawable/logo_white vector has: 200dp width and 100dp height. It looks nice for small devices, but on tablet this logo is too small.
Is it possible to make it responsive for bigger screens?
Many thanks for help.
You can use attribute width and height in API level 23 and higher:
<item
android:width="#dimen/your_size" android:height="#dimen/your_size"
android:drawable="#drawable/logo_white"/>
And create different dimens files, for normal phones, tab, etc
Android has multiple folder system for multiple resolutions.
layout-hdpi,
layout-xhdpi, etc.
and same goes for drawable folder too. So by implementing same filename but edited xml based on dimension for different folder you can make in responsive. You might find other different technique for this.
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?
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
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>
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
<?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
This is on a nexus 10
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>
In Android resources/res folder, create a folder "drawable-xxxhdpi" and "drawable-sw600dp"
In "drawable-sw600dp" folder, add 'splash_logo.png' with resolution 4096x4096 pixels. This should cover tablets.
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!
My code has 5 drawable folders (drawable, drawable-mdpi, drawable-hdpi, drawable-xhdpi, drawable-sw330dp). Each one is used for different screen densities. I have tested each resolution and adjusted accordingly. The only problem so far is that when I test the application on a Droid RAZR, my shapes are drawn incorrectly. The screen size for that particular phone is 540px x 960px.
I have tried three different drawable folder names:
1) drawable-sw330dp
2) drawable-sw540dp
3) drawable-sw225dp << This was suggested by #CommonsWare below
None are adjusting to the xml files that are stored within. It seems like the phone is using the drawable-hdpi instead of going into the specific (sw) folder. Is there another way to make sure that the phone references the right folder?
Example xml file that draws the shapes (used as a background):
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape android:shape="rectangle" >
<solid android:color="#color/menu_active" />
<padding android:left="1dp" />
</shape>
</item>
<item>
<rotate
android:fromDegrees="135"
android:pivotX="96.5%"
android:pivotY="82%"
android:toDegrees="45" >
<shape android:shape="rectangle" >
<solid android:color="#000" />
<padding android:left="1dp" />
</shape>
</rotate>
</item>
The DROID RAZR's screen density should be ~256ppi. Motorola probably put it in the -hdpi density bucket as a result. The shortest width, therefore, would be 225dp, which is smaller than any of your -swNNNdp resource sets.
It looks like drawable-w330dp-normal works for the Droid RAZR. Just create the folder and store the modified drawable there.
Put image resources for MOtorola RAZR in folder: drawable-hdpi
Android supported next formats for drawable assets:
1)drawable-ldpi
2) drawable-mdpi
3)drawable-hdpi
4)drawable-xhdpi
5)drawable-xxhdpi