I have an activity with three rectangle CardViews. I have set the size constraints such that they change according to the screen resolution.
Please view my constraints here.
The problem is that the CardViews are not changing their size proportionally. For example, when I run my application on a Nexus 5 (1080 x 1920), the bottom component gets cut in half, where as if I run on a Pixel (also 1080 x 1920), the bottom component is the desired size.
Although I will try to make the post as clear as possible, the pictures definitely help understand the problem I am facing, so please view them.
..
Why is the bottom component changing so drastically when the screen sizes are very similar? How can I modify the components so that they are the desired size for these different screen sizes?
I know that you are able to create small, normal, large, and xlarge layouts, and I have but I don't think this is what the problem is.
Code for the 3 CardViews:
Top left
<android.support.v7.widget.CardView
android:id="#+id/capture_receipt_cardview"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="#dimen/margin_width_normal"
android:layout_marginEnd="#dimen/button_gap_normal"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
app:layout_constraintBottom_toBottomOf="#+id/create_invoice_cardview"
app:layout_constraintEnd_toStartOf="#+id/create_invoice_cardview"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/create_invoice_cardview">
</android.support.v7.widget.CardView>
Top Right:
<android.support.v7.widget.CardView
android:id="#+id/create_invoice_cardview"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="#dimen/button_gap_normal"
android:layout_marginTop="185dp"
android:layout_marginEnd="#dimen/margin_width_normal"
android:layout_marginBottom="#dimen/button_gap_normal"
app:layout_constraintBottom_toTopOf="#+id/add_single_cardview"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/capture_receipt_cardview"
app:layout_constraintTop_toTopOf="parent">
</android.support.v7.widget.CardView>
Bottom Horizontal:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/add_single_cardview"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="400dp"
android:layout_marginBottom="68dp"
app:layout_constraintBottom_toTopOf="#+id/navigation"
app:layout_constraintEnd_toEndOf="#+id/create_invoice_cardview"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="#+id/capture_receipt_cardview"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0"
app:layout_constraintVertical_weight="0">
</android.support.v7.widget.CardView>
What you are experiencing is brought by the difference in the idea of screen resolution vs pixel density. As mentioned here:
The pixel density is the number of pixels within a physical area of the screen and is referred to as dpi (dots per inch). This is different from the resolution, which is the total number of pixels on a screen.
In your case, Pixel has higher pixel density compared to that of Nexus 5.
To show you the difference, take this formula:
public int dpToPx(int dp) {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}
Given your android:layout_marginBottom="68dp"
Number of pixels in your Nexus 5 phone:
102 = 68 * (240 / 160); // I am assuming the DPI is HIGH
Number of pixels in your Pixel phone:
136 = 68 * (320 / 160); // I am assuming the DPI is XHIGH
Understanding this concept can go a long way in your Android programming career.
Related
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, ...)
I use a LinearLayout (with some content) as the view for my cells in a GridView. The problem is that although I have specified the height of the layout (android:layout_height="50pt") There are some cells that are bigger. The layout is vertical and the items inside have no height(0pt), but they have weight, there are 2 TextViews and 1 ImageView inside. I noticed that the image inside the cells that cause the problem is a bit bigger, but still why would the view grow?
I would appreciate your help.
XML:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="50pt"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="#+id/ivHero"
android:layout_width="match_parent"
android:layout_height="0pt"
android:layout_weight="4"
android:background="#color/white"
app:srcCompat="#drawable/avatar" />
<TextView
android:id="#+id/tvName"
android:layout_width="match_parent"
android:layout_height="0pt"
android:layout_weight="1"
android:gravity="center"
android:singleLine="true"
android:text="TextView"
android:textColor="#color/white"
android:textSize="7pt" />
<TextView
android:id="#+id/tvPercent"
android:layout_width="match_parent"
android:layout_height="0pt"
android:layout_weight="1"
android:gravity="center"
android:text="20%"
android:textColor="#color/white"
android:textSize="7pt" />
Could you try to use dp instead of pt in your layout?
I tested it using dp and pt with different image sizes and it looks different.
Check this out as well
pt - A point, a common font size unit, on the screen. This is a density independent unit, and the physical size of a single pt is the same on every screen density. There are 72 pt in an inch. The number of pixels a single pt translates to varies depending on screen density.
dp - A density independent pixel. This is a density independent unit, however the physical size of a single dp is only approximately the same on every screen density. There are approximately 160 dp in an inch. A scaling factor, depending on the density bucket of the device, is applied to convert dp to the number of pixels at 160 dpi. The number of pixels a single dp translates to varies depending on the pixel on screen density and the density bucket the device falls into.
sp - A scale independent pixel, specially designated for text sizes. This is a density independent unit, however the physical size of a single sp is only approximately the same on every screen density. Scaling factors, depending on the density bucket of the device, as well as the user’s text size preference, are applied to convert sp to the number of pixels at 160 dpi. The number of pixels this translates to varies depending on screen density and the density bucket the device falls into.
for more detailed info you could check this other answer in StackOverflow or on this github repo
Here, you have used "layout_weight" param for all three elements and provide "layout_height" is 0dp. Its wrong.
Whenever you using layout_weight param you should provide "layout_height = match_parent" and "layout_width = match_parent".
Just change layout_height = match_parent and run the app, it will working fine.
Thank you
I found out that I was inflating my view the wrong way and this was the reason why the xml was ignored. This article describes my problem:
https://possiblemobile.com/2013/05/layout-inflation-as-intended/
I was doing it this way:
view = p1 ?: LayoutInflater.from(context).inflate(R.layout.ticket_grid,null)
with a null root, just add the root:
override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
view = p1 ?: LayoutInflater.from(context).inflate(R.layout.ticket_grid, p2, false)
}
i have a image that on mDPI is 360dp and that takes up the entire width of the screen. But when i view the image on nexus 5x api 23 xxhdpi scren it does not take up the entire width of the screen. I thought 1dp equals 1px on MDPI so i could use that as a standard. so then 360dp on MDPI is max width therefore it will be max width on all densities ? what am i missing ?
This is what i have tried. Compare this screens size:
giving this full screen output:
this this one with the same 360dp:
giving a output with the image not taking up the full screen, why :
is this why constraintLayout is recommended , using ratios ?
i finally figured this out. this is one reason constraintLayout was built to rectify these issues. in this particuular case it was about aspect ratio in a view i was using. so to make it take up the entire space of the activity left and right i did the following and the aspect ratio is maintained. keep i mind i wanted a 360 x 500 ratio:
<com.mobile.myapp.customViews.SwippableViewPager
android:id="#+id/pager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="0dp"
app:layout_constraintDimensionRatio="H,360:500"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
this overview was very useful for me to learn constraintLayout.
also the other way to guarantee this would be to use a viewgroup somewhat forgotten now as its deprecated: android percentRelativeLayout
I'm going through a problem in an application here my related to this issue. See if you can help me:
In my case I have a ImageView showing a ruler, and then I need to show this rule in real size, where it does not need to grow or shrink as the screen size or density. Using as a basis my Moto G3, it works perfectly, but when testo other devices, it loses the actual size of a ruler because the image tries to fit the screen size.
The image of the ruler is in PNG and measures 3600px x 155px and has measured up to 30cm, it is within a LinearLayout orizontal. In my Moto G3 visible area it is in 10cm, a larger screen for example it should show a larger area of the ruler (11 to 15cm for example), but it contunua only 10cm in the visual field of the screen, showing that it grows and shrinks as the display settings and density of the device.
Before I had a picture of RAGUA for each resource (xxhdpi, xhdpi, etc), so I decided to migrate it to the assets folder of Android, but still with the same problem.
Do you have a light on how to fix it?
Follows the code:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/rulerPolegada"
android:layout_width="1780dp"
android:layout_height="103dp"
android:layout_marginTop="-10dp"
android:layout_marginLeft="#dimen/left_ruler"
/>
</RelativeLayout>
</HorizontalScrollView>
</LinearLayout>
And as I said, after I image for assets, I started to set it in java:
rulerPolegada = (ImageView) view.findViewById(R.id.rulerPolegada);
rulerPolegada.setImageDrawable(Controller.getImageAssets(getActivity(), "ruler_polegada.png"));
Due to Understanding Density Independence In Android, you can calculate those values as follows
Here is how you can calculate for your device (Moto G3)
30cm = 11.811 in
Moto G3 screen density bucket is xhdpi - 320dpi
320px ~= 1 in
320px * 11.811in ~= 3780px
With this steps you can calculate how big your image should be.
Now, instead of providing different ruler's images for different screen densities, place your high quality image in drawable-anydpi folder, because A drawable in res/drawable-anydpi/ also is valid for any screen density. However, in this case, the -anydpi variant trumps any density-specific variant. due to '-nodpi, -anydpi, and WTF?' article from The CommonsBlog
Unfortunatelly, you can't used calculated values in layout xml file directly - ImageView size needs to be changed dynamically in Java code.
Above solution should give you decent accurancy (it can be diffent by 10%), but you can use DensityMetrics together with default display to get actual horizontal and vertical density, which will help you calculate image pixel size more precisely.
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
// these will return the actual dpi horizontally and vertically
float xDpi = dm.xdpi;
float yDpi = dm.ydpi;
Edit
Calculation for 480dp:
30cm = 11.811 in
density bucket xxhdpi - 480dp
480px ~= 1in
480px * 11.811in ~= 5669px
I'm not sure if you get your answers correct because it appears that previous answers were not satisfied. I had once the same problem - I need this ImageView to have the same size on a plethora of devices without scaling. I solved my problem by providing defined value in dp for layout_width and layout_height
You should read this guide for run in multiscreen
I am having an image in imageview of size 5.64mm.
As android having different resolution,image is varying for different devices.
In my case image should not vary at any device.
please help me with some code for drawing the image or setting the imageview Fixed size.
you have to create the same image for different resolutions and put those images in the hdpi,xhdpi etc folders.
Lets assume your image is 100 x 100 in pixel size, so a device with 320 x 480 pixel will show it big but a device with 1280 x 800 will display your picture smaller.
In other words the more pixels a device has in its per square inch space the smaller space your icon will take.
so you have to create multiple versions of your image so that it size remains relatively same.
Do this way. Use dp unit to specify height and width.
<ImageView
android:id="#+id/ImageThumb"
android:layout_width="55dp"
android:layout_height="60dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginTop="10dp"
android:background="#color/icms_white"
android:padding="1dp"
android:scaleType="fitXY" />
use
android:layout_width="5.64mm"
android:layout_width="6.15mm"