density pixels(dp) is not working fine for all resolutions - android

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#color/gray"
android:orientation="vertical" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#color/darkgray"
android:gravity="center"
android:orientation="horizontal" >
<Button
android:id="#+id/attenders"
android:layout_width="110dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:background="#color/gray"
android:layout_marginRight="8dp"
android:text="Attenders" />
<Button
android:id="#+id/send"
android:layout_width="110dp"
android:layout_height="40dp"
android:layout_marginLeft="8dp"
android:layout_gravity="center"
android:background="#color/gray"
android:text="Send IM" />
</LinearLayout>
</LinearLayout>
this is my code but the dp is not working fine for all screen resolutions.
suggestions plz, plz tell me if i am doing anything wrong

problem is that when i use dp for setting height or width of a button
it does not gets fits to all resolutions i-e on small screens it looks
big and on big screens it looks small, whereas i know that when we use
dp for setting height and width of any component it automatically
converts/adjusts according to screen resolution
What I understand from this is that you thought using dp instead of px (or in, or cm) will magically work such that they will all have the same physical size on all devices, regardless of that device's density (ppi).
That's not the case.
dp, or dip, as explained here, is
An abstract unit that is based on the physical density of the screen.
These units are relative to a 160 dpi (dots per inch) screen, on which
1dp is roughly equal to 1px.
A screen with more dpi (denser, meaning more pixels are packed into a square area of the screen), will essentially draw a physically smaller image compared to a screen that has 160dpi when tasked to draw the same, say, 100x100 dp image.
When running on a higher density screen, the number of pixels used to
draw 1dp is scaled up by a factor appropriate for the screen's dpi.
Solution
There are two easy ways to have your app look proportionally the same on different screen sizes.
The first is to use different layout folders (layout-ldpi, layout-mdpi, etc.). This technique is well-explained here. A much more recommended way would be to use different style values for each density, so you can still maintain one layout folder and refer to the styles instead for measurement. This can be done using the same technique, but instead you will have values-ldpi, values-mdpi, etc. This is useful for having standard sized UI elements across screen sizes.
The other way is to use weights all over your layout. Weights adjust automatically regardless of screen size of density. This will help a lot if you want, say, three columns that have varying width -- you can easily use weights to tell the layout that column A needs to occupy 40% of the available width of the screen, and B and C will have 30% each. This is useful for having a standard layout across screen sizes.
A clean-looking, nicely coded app will implement both.

It is beacause you are giving fixed dimensions which can only be fit for a particular screen size which you are using. So try avoiding static dimensions and make use of match_parent,wrap_content and fill_parent so that you can get your layout fit for every screen size.

Related

Why is widget small although using dp

Sounds like a basic question but I have no idea why this behaviour is that way
I am using a button that is 200 dp by 60dp and with 15sp text size
It looks good on my phone, emulator and multiple other 5 even low 6 inches phones
However on note 10+ which is 6.8 inches, the button looks smaller and the text is smaller
I thought when using dp and sp, it will occupy the same size on all phones given that it is in terms of density independent pixels
Why is this behaviour?
Thank you
Update:
Based on this page about dp size of devices and the link provided at the top of it, I've reached to this article how to calculate metrics of any device including dp. Based on my calculations Note 10+(3040*1440 pixel, 495 ppi) is a 465 * 982 dp device. Google pixel you can see from the first link is a 411 * 731 dp device. So, if you create a size 200 dp layout it would be smaller on the note 10 + than on the google pixel for example. To be honest I thought all small screen devices are something close to a 360 width dp and expected that one design by dp would be seen roughly the same on all devices. I was wrong apparently. It seems if the layout is supposed to be seen exactly the same width on all devices there is no way but to set its width by a percentage of screen width. Google doc has it too: converting pixel to dp.
This image from Support different pixel densities lead me to incorrectly think that designing by dp would be seen the same on all devices. But it would be seen the same only on same dp devices.
It looks good on my phone, emulator and multiple other 5 even low 6 inches phones,
As #Mr. Patel mentioned in his comment, you can use ssp and sdp but I want to offer another solution.
First - why is this happening:
You have a lot of different phones with a lot of different screen sizes, when you are using dp you are actually using a fixed size value - it can not be scaled for large screen.
How to fix it:
You can use ConstraintLayout
with percentage to make your views scale according to the screen size.
Example:
Let`s have a look at this layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="200dp"
android:layout_height="400dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
It will look like this:
In this layout, the button size is 200dp and 400dp.
This may look good on one phone but will not look good on another phone, because as I have mentioned before:
different phones = different screen sizes.
Let`s take a look at how to make your layout responsive according to the screen size:
All I need to do Is to change my layout to this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintWidth_percent="0.3"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
And now the layout will look like this:
Looks... kind of the same?
Well, the new layout is actually looking not so different from the original but now because I have added those attributes:
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintWidth_percent="0.3"
app:layout_constraintHeight_percent="0.5"
For every phone, small or large this button will adjust according to the screen size and will take 30% of the screen width and 50% of the screen Width.
Another tools that can help in the prosses of making some screen responsive:
chains
barriers
How to add different weight to ConstraintLayout views
Autosizing TextViews
dp is base on screen resolution (px) and dpi.
Example:
1280x720px screen of xhdpi (x2)(320dpi) will have 640x360 dp => 1dp = 2 px in that screen.
640x360px screen of mdpi (1x)(160dpi) will have 640x360 dp => 1dp = 1 px in that screen.
The result will look the same for 2 devices
But when the device have a smaller dpi (240) but remain the same resolution: 1280x720px it will have ~854x480 dp
=> 1 = 1.5px in that screen => Your button and text will look smaller.
To make your button look the same on multi screen, you have to provide many dimens file for many screen.
You will have to use many dimens file to make your button show the correct size on other screen. (ssp and sdp is use this way) - (My project have tons of dimens file for each 10dp different screen size to make sure app show the same on any device)
Or you have to use percent supported layout (ConstraintLayout, PercentRelativeLayout, ...)

Android Standard UI development for hdpi

I am relatively new to android. I want to develop an UI which works fine on 2 hpdi devices.
For example lets say on these two devices
Nexus 9
Size 8.86"
Resolution 2560x1600
Density xhdpi
Nexus 10
Size 10.05"
Resolution 2560x1600
Density xhdpi
As seen above both have different screen size and different resolution but density is the same.
My understanding is one layout should work perfectly on both devices, but unfortunately that is not the case. I see differences. Can someone please suggest what changes i should make.
Adding below the portion of the code(xml) which is giving me a problem.
<RelativeLayout
android:id="#+id/rl1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="0.2" >
<customSeekBar
android:id="#+id/abc1"
android:layout_width="wrap_content"
android:layout_height="300dp"
android:layout_marginTop="40dp"
android:thumb="#drawable/eqthumb"
android:progressDrawable="#drawable/progress_eq"
android:max="19"
android:progress="10" />
<TextView
android:id="#+id/abc2 "
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignTop="#+id/ abc1"
android:textColor="#FFFFFFFF"
android:layout_marginTop="-10dp"
android:textStyle="bold"
android:text="300"
android:singleLine="true"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="#+id/abc3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/ abc1"
android:text="0 dB"
android:textColor="#FFFFFFFF"
android:textStyle="bold"
android:singleLine="true"
android:layout_marginTop="-5dp"
android:ellipsize="marquee"
android:textAppearance="?android:attr/textAppearanceSmall" />
</RelativeLayout>
Thank you.
Density is only one part of your layouts though. These devices have different aspect ratios so available device independent pixel (dip or just dp) differs.
So your available width and height differs, but sure logical screen density is the same.
Having said that, android's layouts are rather flexible/adaptable and regardless of screen density. Your layout might need to compensate for different widths or heights though. Just as it might want/need to change due to portrait or landscape mode, different aspect ratios (a potential issue with these two devices) has the same difference.
So you are incorrect in assuming that your layout differs a lot due to hdpi/xhdpi/xxhdpi etc. You might want to qualify your layouts on available screen width or similar (sw720dp for example) instead if needed.
Nexus 9 has a logical screen density of: 1024 x 768 dip
Nexus 10 has a logical screen density of: 1280 x 800 dip
Having said that, your particular layout issue needs your specific xml layouts to be explained. For many layouts those two devices should be able to look the same.
Note: Your device data is off. Nexus 9 is 2048 x 1536 pixels and has an aspect ratio that's 4:3 mind you, compared to 16:10 for the Nexus 10. Both fall in the xhdpi bucket though for resource qualifiers etc. Physical screen density is 288 for the Nexus 9 and 300 for Nexus 10.
As seen above both have different screen size and different resolution but density is the same. My understanding is one layout should work perfectly on both devices
That's not true, you are building on top of this wrong premise. Simply put:
Devices with different screen sizes, but same density, will always work with the same layout
False: different screen sizes (in inches) mean you probably will have to adjust your views. So, provide different layouts, or at least different dimensions.
Devices with different densities, but similar screen sizes, should always work with the same layout
True: if the screen size is the same, a 40dp button will cover the same portion of screen in both devices. That's because dps are density independent pixels, and allow us to work on all densities out there with a single value.
I suggest you read this official resource, that should clear your mind. In the very first bullet list, we read:
Provide different layouts for different screen sizes
Provide different bitmap drawables for different screen densities
As you can see, there's no Provide different layouts for different screen densities, which was the premise of your question. That's just something you don't do usually, it makes no sense if you use (and understand) dps.

Why is wrap_content bigger than real pixel size?

I am trying to understand something. A weird thing that I see is that when I put wrap_content in the width and hight, the image is bigger than the the real px (pixel) size of the image which is inserted. Why is that so?
My code with wrap_content:
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="false"
android:src="#drawable/header" />
and thats my code with exact pixel size of the image:
<ImageView
android:id="#+id/imageView1"
android:layout_width="378px"
android:layout_height="155px"
android:adjustViewBounds="false"
android:src="#drawable/header" />
As you can see, thats the exact pixel size:
Why is that? I thought that wrap_content should wrap the view to the content size so why is it bigger on screen?
If you really need to use the image's pixels as-is, and use the screen actual pixels do the following:
1) Create a res/drawable-nodpi and move your fixed-pixel non-scaling images in there.
2) You then can use wrap_content as layout_width and layout_height, and image pixels will match the device pixels with no upscaling because of dpi.
From http://developer.android.com/guide/practices/screens_support.html, the definition of nodpi :
Resources for all densities. These are density-independent resources. The system does not scale resources tagged with this qualifier, regardless of the current screen's density.
A very nice explaintaion for supporting the multiple screens is given at
http://developer.android.com/guide/practices/screens_support.html.
you need to put images in respective folders after scaling.
e.g. if you want 100*100 image then place
75*75 in drawable-ldpi for Low density devices
100*100 in drawable-mdpi for Medium density devices
150*150 in drawable-hdpi for High density devices
200*200 in drawable-xhdpi for Extra High density devices
wrap_content means that you want the image as it as its original size is. i.e if the size of the image is 200*200 then it will show 200*200 and if the image size is 400*400 it will show of the size 400*400.
So the reason you are getting a larger image then what you actually get when you hard code it with real pixels is because of the LARGE SIZE of the image. i.e image is actually large.
From my experience I can say that wrap_content always utilize maximum available size possible. So sometimes it stretch the image & sometimes reduce the size of the image. To use exact image use android:scaleType="fitXY"
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="false"
android:scaleType="fitXY"
android:src="#drawable/header" />
Update after 1st 2 comments:
as per android docs :
You can specify width and height with exact measurements, though you probably won't want to do this often. More often, you will use one of these constants to set the width or height:
wrap_content tells your view to size itself to the dimensions required by its content
fill_parent (renamed match_parent in API Level 8) tells your view to become as big as its parent view group will allow.
In general, specifying a layout width and height using absolute units such as pixels is not recommended. Instead, using relative measurements such as density-independent pixel units (dp), wrap_content, or fill_parent, is a better approach, because it helps ensure that your application will display properly across a variety of device screen sizes. The accepted measurement types are defined in the Available Resources document.
I found the term size itself is important, it autometically resizes the images. thats why I told that from my experience I found sometimes it stretch the image & sometimes reduce the size of the image
You need to see where you put the image. If its in hdpi it will look bigger on screen then if its in hdpi when ising wrap_content. so, in order for it to be the exact size, put it in right library.

What about percentage usage?

So, i'm thinking about the usage of percent, example, in margins.
We can use overlay to separate our layout by dpi sizes, but why can't we use percentage?
Something like that:
Display display = getWindowManager().getDefaultDisplay();
float width = display.getWidth();
float height = display.getHeight();
//20% of left margin
float imageMarginLeft = ( width * 20 ) / 100;
And then set this margin to the image, or whatever element.
Is this bad? I just wanna discuss about it.
Thanks.
LinearLayout can do percentages by using weight.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="100">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="20"
android:text="Button" />
</LinearLayout>
Weight based layouts hinder performance if you use a lot of them, especially so when they're nested. Doing it programmatically will likely impact layout time as well.
Edit
Since you're looking for discussion, I would suggest that percentage based layouts are bad in general. The problem is that physical screen size varies so much with Android. Half the screen on an Incredible is much different than half the screen on a Galaxy S III, which is much different from half the screen on a Nexus 7, etc. The benefit of using dp units is that they're related to the physical size of things on the screen. It keeps buttons from being tiny (and hard to select) on tiny screens and it keeps them from being enormous (and ugly) on large screens.

Android, images and dpi

I am using WVGA800 skin in Android emulator, so the density (hw.lcd.density) is 240. I have to put 4 image buttons (72 pixels per inch) at the bottom of activities view. As the resolution is 480X800, I asummed that the width of image must be 120 pixels. The problem is when application is launched, the 3 buttons take all width and there is no place for 4th button... Then I created button image in Fireworks with resolution 240 pixels per inch and in 120px width, but problem remains. Could somebody explain how to make correct drawables (sizes and dpi) so that they can be displayed pixel in pixel on Android?
If you put your images in res/drawable, Android assumes they're for 160dpi and scales them accordingly for different resolutions.
Your options are either to put the button images into res/drawable-hdpi signaling that they're intended for densities around 240dpi, or into res/drawable-nodpi to make them never scale regardless of the current screen density.
You still reference them as #drawable/whatever in layouts, the engine picks the best match automatically.
Disregard the image DPI entirely. It's irrelevant, all you need to know is the pixel size. What I would actually suggest is to create a NinePatch image to use as your button background. You'll actually need a few to put into a StateListDrawable, as this is how the different focus states are defined (e.g. Pressed, Focused). Once you have your NinePatch, just create a LinearLayout like so:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/my_nine_patch"
android:text="button 1"
android:layout_weight="1"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/my_nine_patch"
android:text="button 2"
android:layout_weight="1"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/my_nine_patch"
android:text="button 3"
android:layout_weight="1"
/>
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#drawable/my_nine_patch"
android:text="button 4"
android:layout_weight="1"
/>
</LinearLayout>
Set all the buttons to fill_parent and give them all an equal weight. They'll stretch to fit evenly to the parent, and you don't have to worry at all about specifying a constant pixel or dip size. Also, it'll evenly split onto any Android device, no matter the resolution.
The width is actually 320 pixels, so for 4 buttons across the entire screen set each to 80dip. Android will then adjust your density independent pixels to the proper screen size of 480 pixels.

Categories

Resources