Menu Icon Confusion - They're too big! - android

On a "normal" size screen hdpi device, I understand that 72 x 72 pixels graphics should be used, and they should otherwise follow the Icon Design Guidelines (which some of the platform graphics interestingly do not do). When I try to do this by creating my own new graphics or by copying a graphics file from the Android SDK, however, the graphic in the menu is too big, and it forces the text label, i.e., the title, that should be below it to not appear. If I "force" the use of a 48 x 48 pixels graphic, then the size looks good and the text label has room to appear, but this doesn't seem like the right solution, since the graphic display quality is diminished, and the documentation clearly says a 72 x 72 graphic should be used.
I understand the 9-patch graphics should be used to help ensure proper-looking scaling, but none of the menu icon graphics in the platform drawable folders appear to actually be 9-patch, as they don't have any 9-patch markers. For these screenshots, I did add 9-patch markers to a copy of the Android SDK platform 10 72 x 72 hdpi ic_menu_share.png graphic. (The draw9patch.bat tool unexpectedly changed the colors of the graphic.)
In the following four screenshots, I'm showing nine menu icon displays, running on my G2, and running on an emulator with G2-like qualities: Android 2.2 API 8 WVGA800 240dpi. (Both of these devices have "normal" sized hdpi screens.) Since the menu icon graphics will only show six at a time, there are two screenshots for each device: v1 and v2. Following the screenshots are the code components used to generate this application, along with a link to the complete project with all of the graphics files I used.
Emulator_2.2_API8_WVGA800-240_v1:
(Note: In the above screenshot of the emulator, the icon labeled "G2 Platform" should probably instead be labeled "Running Platform", since the displayed graphic is from the currently running Android platform - not from the G2 platform. I was just too lazy to correct this.)
Emulator_2.2_API8_WVGA800-240_v2:
G2_v1:
G2_v2:
(Please note I carefully followed the Icon Design Guidelines when creating and copying these graphics.)
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="fubar.guiexamples"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="8" />
<supports-screens
android:smallScreens="true"
android:normalScreens="true"
android:largeScreens="true"
android:anyDensity="true" />
<application
android:icon="#drawable/icon"
android:label="#string/app_name">
<activity
android:name=".MenuIconConfusion"
android:label="#string/app_name">
<intent-filter>
<action
android:name="android.intent.action.MAIN" />
<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
MenuIconConfusion.java:
public class MenuIconConfusion extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_options_menu, menu);
return true;
}
}
main_options_menu.xml v1:
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/g2_platform_with_title"
android:icon="#android:drawable/ic_menu_share"
android:title="G2 Platform" />
<item
android:id="#+id/g2_platform_no_title"
android:icon="#android:drawable/ic_menu_share" />
<item
android:id="#+id/platform_10_auto_selection_with_title"
android:icon="#drawable/ic_menu_share"
android:title="Platform 10 Auto" />
<item
android:id="#+id/platform_10_auto_selection_no_title"
android:icon="#drawable/ic_menu_share" />
<item
android:id="#+id/pixels_auto_selection"
android:icon="#drawable/ic_menu_pixels"
android:title="Pixels" />
</menu>
main_options_menu.xml v2:
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/platform_10_hdpi_72_with_title"
android:icon="#drawable/ic_menu_share_p10_hdpi_72"
android:title="Platform 10 72 Copy" />
<item
android:id="#+id/platform_10_hdpi_72_no_title"
android:icon="#drawable/ic_menu_share_p10_hdpi_72" />
<item
android:id="#+id/platform_10_mdpi_48_with_title"
android:icon="#drawable/ic_menu_share_p10_mdpi_48"
android:title="Platform 10 48 Copy" />
<item
android:id="#+id/platform_10_hdpi_72_9_patch_with_title"
android:icon="#drawable/ic_menu_share_p10_hdpi_72_nine_patch"
android:title="Platform 10 72 9p Copy" />
<item
android:id="#+id/platform_10_hdpi_72_9_patch_no_title"
android:icon="#drawable/ic_menu_share_p10_hdpi_72_nine_patch" />
<item
android:id="#+id/pixels_auto_selection"
android:icon="#drawable/ic_menu_pixels"
android:title="Pixels" />
</menu>
Some Clarifications Regarding the Screenshots and Code:
As I did for this demo, I understand that we're not supposed to use graphics from android:drawable, for the reasons described in the menu icon design guidelines.
For some of the icons, I dislayed them each twice - once each with a title, and once each without a title - to see whether having a title influenced which graphic was selected and whether the selected graphic was scaled.
The icon labeled "Platform 10 48 Copy" is a 48 x 48 pixel graphic, copied from the Android SDK platform 10 drawable-mdpi folder.
The two lighter colored icons are from the nine patch image. Note they exhibit no scaling characteristics.
The "72" icon was included to show that drawable-hdpi resources are indeed being auto-selected by the running platform, as expected. Were the drawable-hdmi resources instead used, then the displayed number would be "48".
POSSIBLE QUESTIONS:
In a nutshell, I didn't expect much of the results displayed in these screenshots. While I did expect the drawable-hdpi 72 x 72 graphics to be used, I also expected them to display with enough room for the associated titles. So...
I might be asking, "How do I get the menu icon graphics to scale, in order to leave room to dislay the associated title?"
I might be asking, "What size graphics are we really supposed to use for menu icons, nevermind what the official documentation says?"
I might be asking, "What the hell is going on here? What don't I understand?"
The Android project files with the graphics I used can be downloaded from https://sites.google.com/site/androidguiexamples/home/downloads/MenuIconConfusion.zip

All your icons are in the res/drawable directory. So I think the OS is auto-scaling your icons so that they appear as incorrect sizes. They should be split into different directories based on the dpi level the icon is targeted for. 72x72 icons go in res/drawable-hdpi, 48x48 go in res/drawable-mdpi and 36x36 go in res/drawable-ldpi. Note that they should all have the same name.
res/drawable-hdpi/ic_menu.png
res/drawable-mdpi/ic_menu.png
res/drawable-ldpi/ic_menu.png
Then in your menu layout just reference the image using #drawable/ic_menu.png. The OS will then figure out which one to use based on the dpi of the device it is running on.
And as Joseph Earl says, they shouldn't be 9-patch images.

The Android system will select HDPI icons for the target you specified
This will leave enough room for text on the icons
So you might be wondering why you're getting something that looks wrong - simply icons should not be nine-patches, which is why the existing ones did not have nine-patch markers.
A nine-patch is used for a graphic that needs to be resized in a manner that cannot be done by simply scaling/stretching an image (e.g. a button background which expands to fill the content but the corner-radius stays the same, or the window title background). So generally a nine patch is used for a background image of some type.

Related

Android Adaptive icon foreground always too big

I have a problem and I don't know how to solve it.
I am trying to make an adaptive android app icon. That's the code for it:
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="#drawable/launcher_backg" />
<foreground android:drawable="#drawable/logo" />
</adaptive-icon>
That's what it looks like:
As you can see, the foreground is way too big. I don't want that, and I don't know how to fix it. I had a workaround, where I just scaled the foreground until it was small enough. The problem then is, that I don't know what the best size is and all, and I'm sure, there is a better solution.
The foreground is a png and the background a vector graphic.
How can I make the foreground to be the perfect size for an android app icon.
As you can tell from this reference the following sizes need to be provided:
In Android 7.1 (API level 25) and earlier, launcher icons were sized at 48 x 48 dp. You must now size your icon layers using the following guidelines:
Both layers must be sized at 108 x 108 dp.
The inner 72 x 72 dp of the icon appears within the masked viewport.
The system reserves the outer 18 dp on each of the 4 sides to create
interesting visual effects, such as parallax or pulsing.

Android splash screen without logo distortion

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!

Button drawableBottom Nexus 7 and Galaxy Tab 2

I am adapting an application written for a Galaxy Tab 2 (10".1) screen size to a Nexus 7 (7").
Following the suggestions here in stackoverflow I created different image sizes for all densities (l|m|h|xh)dpi and also a specific layout-sw600dp folder which contains my layouts modified for the 7 inches screen.
[EDIT]
And I added
<supports-screens android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true" />
to my Androidmanifest file.
[/EDIT]
Notwithstanding all these modifications I am still struggling having the drawableBottom (and Top, Left, Right) of my Buttons correctly scaling between the two devices.
The physical size of the rendered images is the same. So the Nexus is making the icons as large as the Galaxy (or viceversa).
From what I understood the two devices, although being of different physical size, they share the same density of pixels (xhdpi), that makes the Nexus picking up from the xhdpi folder.
Am I missing something important?
How should I adapt my drawableBottoms?
Have you made sure the app is designed for high density displays? Try adding this to your manifest after permissions:
<supports-screens android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:anyDensity="true"/>
OK.
Probably this is not "THE" solution as it is meant to be. But it worked for me straight away and with a minimum effort considered the size of the application I had to adapt.
This following solution basically works quite nicely but (probably) only for this specific case since the Galaxy Tab 2 and the Nexus 7 share the same resolution.
How I fixed it with almost no work:
Do not create the smaller resolution images (you don't really need it), unless you are going to install (or have installed) your app in many other devices.
Create two values- folders. One for the Galaxy Tab 2 ( = xlarge), the other one for the Nexus 7 ( = large). The modifier is the size of the screen.
Inside each of the folders place a dimen.xml file which you will fill respectively like.
For the Galaxy Tab 2:
<?xml version="1.0" encoding="utf-8"?>
<resources>
[...]
<dimen name="s25sp">25sp</dimen>
<dimen name="s30sp">30sp</dimen>
<dimen name="s35sp">35sp</dimen>
[...]
<dimen name="s25dp">25dp</dimen>
<dimen name="s30dp">30dp</dimen>
<dimen name="s35dp">35dp</dimen>
[...]
</resources>
For the Nexus 7:
<?xml version="1.0" encoding="utf-8"?>
<resources>
[...]
<dimen name="s25sp">17sp</dimen>
<dimen name="s30sp">21sp</dimen>
<dimen name="s35sp">24sp</dimen>
[...]
<dimen name="s25dp">17dp</dimen>
<dimen name="s30dp">21dp</dimen>
<dimen name="s35dp">24dp</dimen>
[...]
</resources>
Each value for the Nexus 7 is obtained like: Galaxy_value/10.1*7
After that you have to use the #dimen/s[0-9]*dp whenever you want to use that specific dimension.
PS:
If you have a big application with many layouts already formatted you could use this PERL script to convert every [0-9]*dp and [0-9]*sp into #dimen/s[0-9]*dp #dimen/s[0-9]*sp automatically.
Here it is:
#!/usr/bin/perl
$filename = $ARGV[0];
open (FILE, $filename);
while (<FILE>) {
chomp;
if ( $_ =~ /\"[0-9]*(di?p|sp)\"/) {
my $pre = $`;
my $mat = $&;
my $pos = $';
$mat =~ s/["]+//g;
print "$pre\"\#dimen/s$mat\"$pos\n";
} elsif ( ($_ !~ /\"[0-9]*dp\"/) && ($_ !~ /\"[0-9]*sp\"/) ) {
print "$_\n";
}
}
close (FILE);
exit;

What images and resource qualifiers do I need to use to ensure that I have a full-screen splashscreen?

I'm writing an application that needs to display a full-screen splashscreen image on start. Actually, not exactly full-screen, because status bar is still visible.
This application will be run on a wide range of phones (e.g. from Wildfire to Sensation), but not on tablets. Though, if it can be made to look good on tablets without much effort, I will do that of course.
The problem is - how can I make sure that this splashscreen looks good and fills the entire screen on all devices? It has stretchable parts on all sides, so I can make it a 9-patch if necessary, but I'm still at loss on what pixel sizes I should use.
I resolve that I need to provide images for (small|large)-(ldpi|mdpi|hdpi). What pixel sizes of those images should be? How to calculate them?
I have done it in multiple applications that i made an image of 480x800px and then took an image view or linearlayout and gave it fill_parent attributes in widht and height. It worked perfectly on all types of screen
[EDIT] One thing more just add that image in hdpi folder only.
For Splash Screen in your xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY"
android:src="#drawable/splash"/>
</LinearLayout>
and in your AndroidManifest.xml
<activity android:name=".Splash" android:theme="#android:style/Theme.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The Theme.NoTitleBar will also remove the title bar from the splash screen
And for the image for splash screen use images of sizes:
As i had read somewhere and then used
For Portrait: 600 x 1024 px
For Landscape: 1024 x 600 px
I use these sizes in my app and have tested them on android versions 1.6 to 2.3 in each version the resolution of the images appears excellent
In the end, I found out that if I provide an hdpi image, it will auto-scale down for lesser dpi. So, to avoid complications, I created a 800x800 image with croppable sides and used it.

How to display icons without alteration in an ImageButton/ImageView?

in my app, I have buttons with icons. The icons are provided as PNG images in the three densities in drawable-ldpi-v4/, drawable/ and drawable-hdpi-v4/. Here's a sample:
Each icon is displayed in an ImageButton:
<ImageButton style="#style/Shortcut" android:id="#+id/open_button"
android:src="#drawable/shortcut_open" android:layout_marginRight="4dp"/>
Where the Shortcut style is:
<style name="Shortcut">
<item name="android:layout_width">65dp</item>
<item name="android:layout_height">45dp</item>
<item name="android:scaleType">center</item>
<item name="android:background">#drawable/shortcut_background</item>
</style>
However, on certain devices/platform versions, certain icons get altered, blurred or something. I'm not sure that it's scaling, it's more like a rendering bug I think. I have tried to disable anti aliasing on the BitmapDrawable, but that didn't help.
As shown on the image below, on Android 2.1 LDPI, one icon gets broken/cropped, and on both Android 1.6 MDPI and Android 2.1 HDPI an extra line seems to be randomly added at the bottom of the icon (look closely).
In the manifest, I have an empty <supports-screens /> as recommended in the docs about supporting multiple screens in legacy apps. Adding anyDensity="true" doesn't help.
Apparently, as of Froyo, things get better as you can see on the image above. But how can I solve this on Android <= 2.1?
I think you should not use explicit sizes (even when expressed as dip) for the buttons, but let the system do it for you.
Use
<ImageButton android:id="#+id/SpeakButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
Also it may be that you are falling into the "dip" vs. "dp" trap that others have reported, where documentation says that they are synonymous, but using "dip" made stuff work as intended.
Not sure if this is the case but you can check if you are not running into the bugs mentioned in this Google I/O talk. I still have to wrap my head around it but I think it's worth having a look if you are targeting platforms from 1.5 to 2.0.

Categories

Resources