Declaring Tablet Layouts for Android 3.2 - mild confusion - android

According to this guide's chapter px = dp * (dpi / 160) and to that layout specifications change from buckets(physical size in inches) to "dp" units so that:
320dp: a typical phone screen (240x320 ldpi, 320x480 mdpi, 480x800
hdpi, etc).
480dp: a tweener tablet like the Streak (480x800 mdpi).
600dp: a 7” tablet (600x1024 mdpi).
720dp: a 10” tablet (720x1280 mdpi, 800x1280 mdpi, etc).
Since "dp" values depend on "px" and "dpi" values so that: dp = px / (dpi / 160) - isn't it possible that a phone device with high resolution will take a layout from w600dp folder?
For instance: Samsung galaxy s3 dp = 1280 / (303 / 160) = 670; Samsung galaxy s2 dp = 800 / (217 / 160) = 592. So, galaxy s3 is going to take "tablet-oriented" template, right. Is it okay, especially if a tablet version contains more elements and overall interface ergonomics gonna suffer from the tablet layout in case of s3 ? Why don't just stick to display buckets ?
You're probably going to recommend using "sw" key but I just want make sure that those "dp" units actually relate to sizes so that tablet-oriented template won't be shown on phone devices.
So, would you mind sharing your practical knowledge on applying the new approach ?
Thanks

A dp or dip is a (screen) Density Independant Pixel. The confusing part about that is that is mentions pixel. It is actually a unit similar to a centimeter or inch.
Each device defines a dpi bucket for it's screen, for example mdpi which is 160dpi. That means that you find 160 pixel across one inch on the screen. It's not 100% accurate since physical screens are usually not exactly 160 dpi (or whatever value that is defined for the bucket). But it's a value that comes close.
That means that 160dp on a perfect 160dpi screen are actually 160 pixel. On a device with a perfect xhdpi (=320dpi) screen those 160dp would be 320 pixel. (px = 160dp * (320dpi / 160))
To work with dp don't think in pixel. Think in inch, milimeter or what unit you prefer. The recommended 48dp rythm for UI elements for example explains that
On average, 48dp translate to a physical size of about 9mm (with some variability)
To approximate that: 50dp = one finger wide.
That hopefully explains why a typical 320dp phone screen is always smaller than a 720dp tablet screen although the smaller screen can have more pixel than the larger. The dpi / pixel thing is already factored into dp.
How to do different layout for different screensizes? (i.e. phone vs table)
Use the screen size buckets (small, ..., xlarge) for the layout. They represent physical small to large screens. You don't need sw600dp etc unless you need to adjust very special cases.
The different dpi buckets should only concern you for images. E.g. high resolution images for high resolution screens of any size in the drawable-hdpi folder.

The S3 does not have a density of 160.

Related

how to design any screen size and - density in Android(Multi screen for mobiles in Android)

How to handle design in multi screen for mobiles in Android without using dimention in values folder.
My application it's support all android mobiles, and I had a problem with the design, because I'm using dimen in values folder to handle it.
So please anyone can help me to handle this problem without using the dimention.
layout compatibility is very important part of any project
sorry but you have to use dimens for handle this problem.
and i think best way for design is use density.
you can use dimens-hdpi or dimens-mdpi or ...
and can use dimens-small or dimens-large or ...
and can use both of them together. like dimens-larg-mdpi
but this is so hard to design.
i using dimens smallest screen width
this use density and i think you can handle all of phones or tablets by 4 or 5 dimens.
like this picture.
Typical numbers for screen width dp are:
320: a phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).
480: a tweener tablet like the Streak (480x800 mdpi).
600: a 7” tablet (600x1024).
720: a 10” tablet (720x1280, 800x1280, etc).
if you have a device don't support by one of these you can add
another smallest screen width for that.
you can read more details here , here , here and this help you know your phone pixels per inch.
example:
you have a phone 1080*1920 pixel and 5" size.
first formula help you calculate pixel per inch (dpi).
second formula help you calculate Pixel ratio.
and last formula help you calculate dp.
this phone have 392 dp in width and smallest width for that is 320.
if you like use dpi Pixel ratio can help you.
ldpi => Pixel ratio = 0.75
mdpi => Pixel ratio = 1.0
hdpi => Pixel ratio = 1.5
xhdpi => Pixel ratio = 2
xxhdpi => Pixel ratio = 3
xxxhdpi => Pixel ratio = 4
if you want to support all resolution (ldpi ,mdpi ,hdpi , xhdpi , xxhdpi , xxxhdpi ) then you can put your images those folders.
For text sizes its a good practice to use dimension folder. But if you do not want to use dimension folder then you can pick resolution of device programatically and change your text sizes
mipmap-hdpi, mipmap-mdpi,mipmap-xxhdpi, this folder are you that u need to use them for diffrent resolution
you can read : http://developer.android.com/guide/practices/screens_support.html

Putting screen densities into the correct bucket

A set of six generalized densities:
ldpi (low) ~120dpi
mdpi (medium) ~160dpi
hdpi (high) ~240dpi
xhdpi (extra-high) ~320dpi
xxhdpi (extra-extra-high) ~480dpi
xxxhdpi (extra-extra-extra-high) ~640dpi
From the wiki pages of each phone display
Scaling down into the buckets i.e if the ppi is 300 that would go into the hdpi bucket as it less then 320?
Galaxy S3 306ppi -> bucket hdpi
Nexus 4 318ppi -> bucket hdpi
Nexus 5 445ppi -> bucket xhdpi
Nexus 5X 432ppi -> bucket xhdpi
Nexus 6 493ppi -> bucket xxhdpi
Nexus 6P 518ppi -> bucket xxhdpi
Is this the correct way to work out buckets for screen sizes.
The reason I asked is because I have created the following value directory resources:
values-hdpi/dimens
values-xhdpi/dimens
values-xxhdpi/dimens
values-xxxhdpi/dimens
In the dimens.xml I have different margins and set the dp depending on the bucket size i.e.
<dimen name="network_quantity_margin_top">100dp</dimen>
I am interested to know if this is the correct way to do this.
The reason I asked is because I have created the following value directory resources. (...)
In the dimens.xml I have different margins and set the dp depending on the bucket size. (...)
I am interested to know if this is the correct way to do this.
I'm not sure why you want different margins specified in dp depending on the density. Specifying the margin as dp once, for the baseline density, already handles all other densities for you, meaning that the physical size of the margin will be the same when displayed on any device.
If you used px instead of dp (but don't), then you would have to do the scaling for different screens yourself.
Scaling down into the buckets i.e if the ppi is 300 that would go into the hdpi bucket as it less then 320?
Yes, but not because it is less than 320. If there was a rule of thumb I would say it is rounding to the nearest generalized density. See this illustration of how Android roughly maps actual densities to generalized densities (figure is not exact):
Relevant part of the documentation is this:
Each generalized size and density spans a range of actual screen sizes and densities. For example, two devices that both report a screen size of normal might have actual screen sizes and aspect ratios that are slightly different when measured by hand. Similarly, two devices that report a screen density of hdpi might have real pixel densities that are slightly different. Android makes these differences abstract to applications, so you can provide UI designed for the generalized sizes and densities and let the system handle any final adjustments as necessary.
So again, you shouldn't really care how Android does this if you are just writing an app. What you should care about is:
specify all layout dimension values in dp or with wrap_content/match_parent, as appropriate (text can be in sp to additionally match the user preference, but nothing other than text),
think about different layouts depending on physical size and orientation of the screen,
provide bitmap resources for different densities, just to avoid blurry or pixelated artifacts (because Android will scale them to have the right physical size if you use dp or wrap_content).
Android will lookup the best matching resource, and then transparently handle any scaling of the dp units, as necessary, based on the actual density of the screen in use. The conversion of dp units to screen pixels is simple: px = dp * (dpi / 160).
Note the actual density as opposed to generalized density. The latter is only a convenience for the developers, since it would be impossible to provide drawables for every screen out there. This way developers need to provide only 3 or 4 sets of graphics, while Android picks the closest fit and adjusts it further for the needs of that particular device. (Nowadays it's possible to use one vector drawable instead of many pre-scaled raster graphics, meaning better quality and less size.)
Is this the correct way to work out buckets for screen sizes.
No, it is not. According to Google device metrics all devices you listed fall into buckets higher than you expected:
Galaxy S3 NA NA
Nexus 4 318 xhdpi
Nexus 5X 424 xxhdpi
Nexus 5 445 xxhdpi
Nexus 6 493 xxxhdpi
Nexus 6P 515 xxxhdpi
I took some other devices from that list, and plotted how different devices are falling into density buckets depending on their actual physical density.
Chromebox 30 101 mdpi
Chromebook 11 135 mdpi
Samsung Galaxy Tab 10 149 mdpi
Nexus 7 '12 216 tvdpi
Android One 218 hdpi
Chromebook Pixel 239 xhdpi
Nexus 9 288 xhdpi
Nexus 10 299 xhdpi
Moto X 312 xhdpi
Nexus 4 318 xhdpi
Nexus 7 '13 323 xhdpi
Moto G 326 xhdpi
Dell Venue 8 359 xhdpi
LG G2 424 xxhdpi
Nexus 5X 424 xxhdpi
HTC One M8 441 xxhdpi
Nexus 5 445 xxhdpi
Nexus 6 493 xxxhdpi
Nexus 6P 515 xxxhdpi
LG G3 534 xxhdpi
You can see, that with some notable exceptions, the rule that the closest generalized density is selected, holds.
The exceptions being Nexus 6 and 6P, that are listed as xxxhdpi, even though LG G3 has a higher physical density and still is far from 640px/in. Android One is hdpi but it is only slightly denser than Nexus 7 '12 which is tvdpi. Chromebox 30 and Chromebook Pixel (admittedly, not Android) are assigned to buckets mdpi and xhdpi even though they are physically lower than ldpi and hdpi, respectively.
I am interested to know if this is the correct way to do this.
You are mostly correct.
The problem lies in this part:
The reason I asked is because I have created the following value directory resources:
values-hdpi/dimens
values-xhdpi/dimens
values-xxhdpi/dimens
values-xxxhdpi/dimens
In the dimens.xml I have different margins and set the dp depending on the bucket size i.e.
<dimen name="network_quantity_margin_top">100dp</dimen>
The purpose of dp gets defeated by defining folders like values-hdpi/dimens. Density Pixels, by design, are device-agnostic - 100dp on a device with dpi = 240 will look just as wide/long on a device with dpi = 480. So, if you want your app to look consistent, do not provide different dimensions for different screen densities.
The correct way to think about this is to realize that the only resource that is affected by varying screen densities is drawable. A drawable on a screen with dpi = 240 will look twice as big compared to a screen with density = 480. I am sure that you're providing folders like drawable-hdpi, drawable-xhdpi etc. to deal with this. For everything else, and especially dimensions, use dp. For text sizes, use scaled-pixels - sp.
More importantly, you should worry about the range of different screen sizes that are available for android. How would you use all the extra screen real-estate on a 10 inch device compared to a 5 inch phone? Qualifiers such as -normal, -large, xlarge should be of more interest to you.
To summarize:
consider all devices of a certain screen size the same - their screen densities are irrelevant when using density pixels.
for every drawable resource you use, place their scaled versions in the buckets you wish to support. Remember that, if you don't provide resources for a certain bucket (say drawable-hdpi), android will scale down your drawables from drawable-xhdpi folder (provided drawable-xhdpi is defined). The reverse is also true: if you have placed all your drawables in drawable-xhdpi, android would scale-up your drawables on a xxhdpi device. The result will be blurry graphics - because of scaling-up.
I know that its a bit of a steep slope here :). So, if you need to clarify some more, leave me a comment.
From the Android documentation:
Supporting Multiple Screens
In some cases, you will need to express dimensions in dp and then
convert them to pixels. Imagine an application in which a scroll or
fling gesture is recognized after the user's finger has moved by at
least 16 pixels. On a baseline screen, a user's must move by 16 pixels
/ 160 dpi, which equals 1/10th of an inch (or 2.5 mm) before the
gesture is recognized. On a device with a high-density display
(240dpi), the user's must move by 16 pixels / 240 dpi, which equals
1/15th of an inch (or 1.7 mm). The distance is much shorter and the
application thus appears more sensitive to the user.
To fix this issue, the gesture threshold must be expressed in code in
dp and then converted to actual pixels. For example:
// The gesture threshold expressed in dp
private static final float GESTURE_THRESHOLD_DP = 16.0f;
// Get the screen's density scale
final float scale = getResources().getDisplayMetrics().density;
// Convert the dps to pixels, based on density scale
mGestureThreshold = (int) (GESTURE_THRESHOLD_DP * scale + 0.5f);
// Use mGestureThreshold as a distance in pixels...
The DisplayMetrics.density field specifies the scale factor you must
use to convert dp units to pixels, according to the current screen
density. On a medium-density screen, DisplayMetrics.density equals
1.0; on a high-density screen it equals 1.5; on an extra-high-density screen, it equals 2.0; and on a low-density screen, it equals 0.75.
This figure is the factor by which you should multiply the dp units on
order to get the actual pixel count for the current screen. (Then add
0.5f to round the figure up to the nearest whole number, when converting to an integer.) For more information, refer to the
DisplayMetrics class.
you have to handle the resources regarding the screen width in dp not dpi(dot per inch)
for example nexus 5 1920 X 1080 480 dpi it uses xxhdpi
and nexus 6p 2560 X 1440 560 dpi it uses xxhdpi too not xxxhdpi !!
to handle it use the smalest width resource "drawable-swXXXdp"
width in dp = width in pixle / (dpi/160)
dp= 1440/(560/160) =~ 411
create drawable-sw411dp
Reference
When speaking about Android devices, PPI == DPI
PPI (Pixels Per Inch) and DPI (Dots Per Inch) mean the same thing since they are a measure of the density of the screen; thus, your approach about PPI vs DPI is correct.
A detailed explanation can be found here. The key part of the article is the following:
The screen density is quoted as Pixels Per Inch, PPI, and is the
number of pixels that fit into an inch. The higher the number then the
sharper images look on the display, therefore consumers consider a
high PPI figure an advantage when buying a device. Sometimes the
figure is quoted as Dots Per Inch, DPI ...
Bit late, but this may be useful to other readers. Screen density and the "bucket" Android uses to pick a resource from can be confusing. Google's documentation is pretty dense, and it takes alot of work to distill it down to something useful when writing code. Partly because there are several factors and they're telling you everything about screen density and dips. But the short answer is this.
Basically, dpi is your defining factor, (if you rely on other factors like small/medium/large), this is not your answer. Otherwise, I found this answer quite helpful and simple. Here is some code I have collated from various sources that I run on app startup to determine display information.
The screen density tells me what dpi level the device supports.
float density = context.getResources().getDisplayMetrics().density;
Next I have a simple device metrics method to tell me about the screen. (Note, I am using Timber logger).
protected static void checkDeviceSize(AppCompatActivity context) {
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
Display display = context.getWindowManager().getDefaultDisplay();
DisplayMetrics outMetrics = new DisplayMetrics();
display.getMetrics(outMetrics);
float density = context.getResources().getDisplayMetrics().density;
float dpHeight = outMetrics.heightPixels / density;
float dpWidth = outMetrics.widthPixels / density;
String dpiName = getDpiName(density);
Timber.e("density :" + density + " [" + dpiName + "]");
Timber.e("height dp:" + dpHeight + ", (" +outMetrics.heightPixels + "px)");
Timber.e("width dp :" + dpWidth + ", (" + outMetrics.widthPixels + "px)");
}
I also have this simple helper method that determines the DPI name to support the method above.
public static final String DPI_LDPI = "ldpi";
public static final String DPI_MDPI = "mdpi";
public static final String DPI_HDPI = "hdpi";
public static final String DPI_XHDPI = "xhdpi";
public static final String DPI_XXHDPI = "xxhdpi";
public static final String DPI_XXXHDPI = "xxxhdpi";
public static final String DPI_TVDPI = "tvdpi";
private static String getDpiName(float density) {
String result = "undefined";
if (density < 1.0) {
result = DPI_LDPI;
} else if (density == 1.0f) {
result = DPI_MDPI;
} else if (density <= 1.3f) {
result = DPI_TVDPI;
} else if (density <= 1.5f) {
result = DPI_HDPI;
} else if (density <= 2.0f) {
result = DPI_XHDPI;
} else if (density <= 3.0f) {
result = DPI_XXHDPI;
} else if (density <= 4.0f) {
result = DPI_XXXHDPI;
}
return result;
}
Finally this video from 2013 is still relevant today.

Confusion with "smallest width 600 dp" selector

In my application I am supporting phone/tablet form factors and to have individual layouts I use selector "layout" (for phones), "layout-sw600dp" (for tablets).
Following are the details:
http://android-developers.blogspot.in/2011/07/new-tools-for-managing-screen-sizes.html
Typical numbers for screen width dp are:
320: a phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).
480: a tweener tablet like the Streak (480x800 mdpi).
600: a 7” tablet (600x1024).
720: a 10” tablet (720x1280, 800x1280, etc).
I am having a Nexus 4 mobile, following are its attirbutes
Size: 4.7 inches
Resolution: 768 x 1280 pixels
DPI: 318
dp: 386
Here is the dp calculation
dp = (px * 160)/dpi
dp = (768 * 160)/318
When I use 768 px in dp calculation formula the dp value comes as 386, but when I pass 1280 px the dp value comes as 644.
With the following understanding I thought for Nexus 4 landscape it would read the layout from sw600dp, but that's not the case.
As the resolution is width X Height, it will be reversed when the device is rotated.
I thought this is the improvisation made with sw selectors compare to pre-3.2 large, xlarge sectors.
As it says in the Android documentation here in bold (scroll down a bit to the "smallestWidth" section of Table 2):
The smallestWidth is a fixed screen size characteristic of the device;
the device's smallestWidth does not change when the screen's
orientation changes.
The sw figure is always the shorter of the two screen dimensions, regardless of the device orientation. That's where the "smallest" in the name "smallestWidth" comes from. The advantage over Gingerbread-style "large" &c. selectors is only that you get more granularity of control, and it's more predictable what screen sizes you'll actually get, because it doesn't rely on how the manufacturer classes their screen size.
If you want to select a layout based on the width or height of the screen in its current orientation, use a directory called layout-w600dp or layout-h600dp.

Trying to define which layout should a device use

I'm trying to understand which layout uses which device.
For instance, I've different layouts:
layout
layout-sw600dp
layout-sw720dp
Nexus 7" (800x1280) uses layout-sw600dp
Samsung GTp3100 7" (600x1.024) uses layout-sw600dp
Samsung Tab 10.1 (1280x800) uses layout-sw720dp
Sony XPERIA S 4.3 (1280x720) uses layout
Can you guys explain "with your words" why isn't XPERIA S using sw600dp or sw720dp?
SW != smallest width? So smallest with from XPERIA S is 720. It should be using sw720 or sw600, right? Or am I wrong?
I've read tons of documentation, but can't understand why is this happening.
Thanks a lot.
The Smallest-Width qualifier refers primarily to screen size and not the physical pixels.
Using sw720dp for example means the device must have a minimum screen width of 720 dp (device-independent pixels) - this isn't about 720 physical pixels. From the documentation...
The density-independent pixel is equivalent to one physical pixel on a 160 dpi screen, which is the baseline density assumed by the system for a "medium" density screen.
The physical width of the Sony XPERIA S 4.3 is 2.5" but I don't know how much of that is the actual width of the screen.
Let us pretend for the sake of calculations that the screen covers the full width...in this case to calculate dpi for width we simply use 720 / 2.5 = 288dpi.
From the documentation for dp...
The conversion of dp units to screen pixels is simple: px = dp * (dpi / 160).
Rearranging the formula above to calculate dp we do this...
dp = px / (dpi / 160)
...this gives us the width in dp (and a necessary Smallest-width qualifier) of...
720 / (288 / 160) = 400dp
In short the answer is, the Sony XPERIA S 4.3 may have a high-density screen (for its size) but it isn't a large screen.

Asset Creation - 9patch SplashScreen and ScreenDensity

So I get the whole Android pixel independency thing.
I'm creating a SplashScreen that is using a 9patch that will stretch its edges to account for all screensizes.
I also use a differenlty sized 9patch image in ldpi mpdi hdpi xhdpi for each splash screen as well.
That way the logo (the non stretched area of the 9patch) will be the correct size.
I know mdpi is 1.0 and hdpi x1.5 in relative size and xhdpi is x2, but when I'm creating that first mdpi image how do I know how many pixels wide/high it should be?
Hope that makes sense.
Really there's no one answer. Firstly though, I wouldn't start at mdpi and scale up -- It's best to start at the highest quality that you can. Vector, if it fits the design, or a high resolution image (even larger than the largest screen size you currently plan to support). Then, from there, just downsize for the device that you plan to test. For example, a typical HDPI resolution would be 480 x 800, so fit it appropriately there. An XHDPI resolution might be something like 1280 x 720. It's best to just leave a good amount of margin on the edges in case it's used on a device with a different aspect ratio, or something. But yeah, basically, design as large as you can, and then just export based on some average screen resolutions for the density bucket you're working on.
(...) when I'm creating that first mdpi image how do I know how many pixels
wide/high it should be?
Since mdpi is the baseline for all other density buckets, 1dp on an mdpi device will translate to exactly 1px. In other words, use an mdpi device to figure out the relative size on the screen and from there on apply the given scaling ratios to produce resources for the ldpi, hdpi and xhdpi buckets. Obviously you do not actually have to scale up that mdpi resource - all you need determine is the size for that screen density and then you can use whatever source file to produce images for all buckets.
The link xBroak has given, is actually the best source of information regarding your question. A quote from there to support above statements:
The density-independent pixel is equivalent to one physical pixel on a
160 dpi screen, which is the baseline density assumed by the system
for a "medium" density screen.
It may also come in handy to be aware of the simple d(i)p to px formula (also from that same link):
The conversion of dp units to screen pixels is simple: px = dp * (dpi
/ 160)
With this information, you can easily verify that 1dp on an mdpi device (with 160dpi screen) is equal to 1px. Just fill in 160dpi and you get px = dp * (160 / 160), which simplifies to px = dp * 1, and hence px = dp for 160dpi. QED. :)
These are your basic guidelines:
xlarge screens are at least 960dp x 720dp
large screens are at least 640dp x 480dp
normal screens are at least 470dp x 320dp
small screens are at least 426dp x 320dp
320dp: a typical phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc).
480dp: a tweener tablet like the Streak (480x800 mdpi).
600dp: a 7” tablet (600x1024 mdpi).
720dp: a 10” tablet (720x1280 mdpi, 800x1280 mdpi, etc).
More info: http://developer.android.com/guide/practices/screens_support.html

Categories

Resources