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, ...)
Related
I'm developing an app and my Constraint Layout isn't compatible with any screen size.
I have a button with the following width and height:
android:layout_width="283dp"
android:layout_height="57dp"
Here's how it look using a Google Pixel.
And here's how it looks using a Nexus S
I also sent the apk to a person that has an Galaxy J7 (1280x720, 5.5'), and my buttons, textviews and imageviews don't fit well in the screen, just like the Nexus S (800x480, 4').
After reading the documentation and other sources, I got that I can create different layouts for different screens (hdpi, for example, which is the case of the Nexus S).
But it looks that the problem is more related to the display inches than with the device dpi.
Because the Nexus S has an 800x480, hdpi and 4' screen. But when I change to a 800x480, mdpi and 5.1' screen (1.1' more inch), it looks way better than in the Nexus S, even with a lower dpi (mdpi). It also looks better than in the Galaxy J7 real device, even with a lower screen size (5.1' x 5.5') and resolution (800x480 vs 1280x720).
So, how can it fit well in a 800x480 5.1' mdpi screen, but not in a 1280x720 5.5' Galaxy J7 and in a 800x480 4.0' hdpi screen (Nexus S)?
Also, if I create a virtual device with the same screen specs of the Galaxy J7 real device (1280x720 and 5.5'), It fits really well, unlike the real phone.
I advise you to use Adobe XD and use it to determine the size
android:layout_width="283dp"
android:layout_height="57dp"
and after that extract the pictures for all sizes
Then make the width and height wrap_content
In the XML file
You can replace your fixed size (what you are currently giving to your views) with something more responsive.
If this was your non responsive button:
<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" />
Just replace it with this:
<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" />
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.
This is how you can make one screen responsive to all screen sizes and not create a lot of layouts for different screens.
These images are OK, it's not a problem itself. That's usually what happens when you set the width and height manually.
Best thing you can do is set the right constraints and then set width and/or height to 0dp. This will make your view expand as much as possible without breaking any constraint. This way you will still get different widths and heights, but hopefully less noticable ones.
Be aware that if you set top and bottom constraints to parent, and you set the height to 0dp, it will expand to fill its contraints, it will fill your whole parent.
And for positioning you can use guidelines if you want. A a horizontal guideline in 50% will be in the middle of the screen in every phone. So you can constrain views to that as well.
I am designing an app which needs the customized button. I made it by inheriting the Android Button and I set its width to 300dp in the layout xml. However, I found the size of button is changing on different devices. Here are the example:
My UI in the original device: Galaxy S5
My UI in the new device: Nexus 5X
My UI in another device: Galaxy Note4
(In this trial, I set the left button to use sp instead of dp)
It seems the whole layout scale is smaller in my new device even though both of them are 1080 x 1920 pixels.
I also try to use sp but it behaves the same (problem). My guess is the style? Can any one gives me more thoughts. Thanks!
--- UPDATE ---
Hi, let me rephrase my problem.
I am looking for a way to make a button which width is fix to like (relatively) 1/3 screen width at any device. And its text also changes accordingly. I think the ultimate way is to translate everything to pixel and assign those value manually in program. I used to think using dp and sp is an easy alternative to achieve it, but it turns out not :(
To set width of each child programmaticaly,
view.getLayoutParams().width = getScreenWidth() / VIEWS_COUNT_TO_DISPLAY;
And Screensize as below
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics).widthPixels;
Now, If you want to set Text than use SP for that.
If you are using dp then it will change according to device's screen density. In order to keep the button size same in different screen density conditions you need to use pt,in or mm in your button's width.
Please check link : What is the difference between "px", "dp", "dip" and "sp" on Android?
I think here is what you want.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal"
android:weightSum="3">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="1">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="#drawable/test"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Normal Charge (Testing)"/>
</LinearLayout>
</LinearLayout>
With the use of weightSum and layout_weight, you can fix the item as 1/3 width of your screen.
Inside the imageview, android:scaleType="fitXY"
It means that the image will be changed to size in order to match the size of imageview.
You can delete that attribute if you do not want that.
For the image, the best way is to prepare different size of the image inside different folders:
for mdpi it should be 100X100
for ldpi it should be 75X75
for hdpi it should be 150X150 (e.g. Xperia U)
for xhdpi it should be 200X200 (e.g. Galaxy S3, Galaxy Note II, Xperia S)
for xxhdpi it should be 300X300 (e.g. Galaxy S4, Galaxy S5, Xperia Z, Xperia Z1, Xperia Z2)
The above size is just an example, you have to find the base case, i can explain more about that if you need.
Hop that can help, thanks!
I know the Internet is overwhelmed with questions about DPI px inches and so on.
But after several hours of googling my situation doesnt seem to happen to anyone else!
I have 2 devices custom build with android studio which are both mdpi.
BUT one device is 3.65inch and the other device is an 10.1 inch.
I have created a folder with 2 images 250x125 with the dpi set to 160 dpi
If normally I would declare my 2 images in my XML with dp units instead of pixels...I would suppose on both screens the result should be the same right ?
Well it seems the images keep remaining the same size and don't look # how many inch the device is
So to set things clear:
What do I have to change at my resources or my code so that my layout scales identical for different Inch sizes ?
This is my GOOD layout for my mdpi 10.1 tablet :
This is my BAD layout for my mdpi 3.65 device
How can I make it so that even on the 3.65 inch screen the buttons will scale to the same PROPORTIONS as the 10.1. Not the inches...not the pixels...the proportions....
This is my XML File
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
android:gravity="center">
<Button
android:id="#+id/buttonEnglish"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/english"
android:layout_marginBottom="5sp"
android:layout_marginLeft="5sp"
android:layout_marginRight="2sp"
android:layout_marginTop="0sp" />
<Button
android:id="#+id/buttonNederlands"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/nederlands"
android:layout_marginBottom="5sp"
android:layout_marginLeft="20sp"
android:layout_marginRight="5sp"
android:layout_marginTop="0sp"
/>
</LinearLayout>
I'm desperate...
Thanx in advance
This might help explain the problem you are facing...
You have an image that is 250x125 - that is 250 pixels wide by 125 pixels in height.
You have specified 160 dpi - which means that 1 inch = 160 pixels.
So, both screens are doing what you ask and displaying the 250 pixels across 1.5625 inches. On the large screen it looks "proportionally" correct. On the 3.65" screen the button takes up more than half the screen - just like you asked it to.
If you want the smaller screen to look like the larger screen, then you have three options:
adjust the size of the image and provide 2 image assets (or more for a wider variety of screens). This is why you can have resource folders for mdpi, hdpi, xhdpi, etc. You adjust the pixels in the image to accommodate the screen size.
You use a "weighted" LinearLayout that adjusts the size of the space provided based on the available screen space. For this type of layout you should not worry about performance.
Do runtime scaling of the image based on screen size - use DisplayMetrics to get the size and density of the screen and adjust your image to fit the screen appropriately.
The last option is the most flexible in many ways, because if you end up with a screen that is either very large or very small, you can make adjustments to do things like move buttons or text to another place on the screen (above or below other content). But for your specific problem, any of them will suffice.
There is no need of Designing two xml layout.
You can use Dimension for margin and padding according to device.
You are giving static value for margin.
Use dimen.xml in value folder each device.
Following code in your layout.xml will work for you.
android:layout_marginLeft="#dimen/margin_button"
Value folder name for dimen.xml:
values-mdpi
values-hdpi
values-xhdpi
values-xxhdpi
values-sw600dp
create dimen.xml in each values folder.
and in dimen.xml you have to define value for margin in all values folder but value of that property is different according to device size like this:
values-mdpi
<dimen name="margin_button">20dp</dimen>
values-hdpi
<dimen name="margin_button">23dp</dimen>
like wise in all values folders.
Thanx everyone for the answers. Due to answer from #Iacs I discovered that I had to made changes to my folder structure.
I have completely overlooked the fact that in the /res folder there can be more directories then just the standard "layout" directory. You can create other directories with these names : layout-large, layout-xlarge, layout-small, and so on...
In these folders you can paste your layout.xml and adjust the values...
This is how things look now in my android studio
note the layout folder structure:
And now ofcourse my 2 devices with both the same DPI but different screen size are showing my buttons the way I want them to be showned!
<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.
I faced with a strange problem with my widget size.
I decided to develop one simple widget with supporting of ldpi, mdpi, large-mdpi and hdpi screens.
At first I created xml/widget.xml where I defined the following:
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
android:minHeight="146dip"
android:minWidth="220dip"
android:updatePeriodMillis="0"
android:initialLayout="#layout/widget"/>
So I expect that my widget will take 3x2 cells for all supported screens.
Then I designed several layouts, one for each screen type - ldpi, mdpi, large-mdpi and hdpi - where:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/Widget"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
...
</RelativeLayout>
So I expect that the widget size will fit 3x2 cells for all screens, not more, not less.
But currently when I run it on emulator (and real device too) I see that my widget takes
more than a half of a screen for all supporting screens - 4x3 cells if
to talk that the max size is 4x4 cells (as it described here:
http://developer.android.com/guide/practices/ui_guidelines/widget_design.html#sizes).
Even if I'll define exact layout_width and layout_height in my widget
layouts in dip it will still take 4x3 cells, just it's visible part
will have another size.
Well, looks like emulator not always refresh my app and that is why I saw my old dimensions instead of new. My friend also said that emulator usually doesn't update apps if using startActivityForResult. So in that case it is better to restart widget manually. Hope that will be helpfull for someone else :)
From http://developer.android.com/guide/topics/appwidgets/index.html
Because the Home screen's layout orientation (and thus, the cell sizes) can change, as a rule of thumb, you should assume the worst-case cell size of 74 pixels for the height and width of a cell. However, you must subtract 2 from the final dimension to account for any integer rounding errors that occur in the pixel count. To find your minimum width and height in density-independent pixels (dp), use this formula:
(number of cells * 74) - 2