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)
}
Related
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.
In my Android app I have the following layout:
<android.support.v7.widget.CardView
android:id="#+id/difficultyCardView"
app:layout_widthPercent="60%"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:cardUseCompatPadding="true"
android:layout_centerHorizontal="true"
android:layout_above="#+id/noHighScoresCardView">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/yellow"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="10dp"
android:src="#drawable/pushpin" />
<TextView
android:id="#+id/diffNameTv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="12dp"
android:maxLines="1"
android:singleLine="true"
android:text="FÁCIL"
android:textSize="20sp"
android:textStyle="bold" />
</LinearLayout>
</android.support.v7.widget.CardView>
In my Nexus 5, setting the text size to 20sp as shown above, makes text occupy, approximately, 75% of CardView's width. The problem is that, when I test this on a smaller phone, it adds ellipsis to the text.
What I want to achieve is that, on EVERY screen size and resolution, the text will exactly occupy 75% of the card with.
So, how can I solve this problem, creating multiple scale folders (ldpi, mdpi, ...) and adjusting font size in each of them, calculating it via code as a percentage, or any other solution?
Thank you.
Get the card width on the specific device and multiply by .75, then set the text size to that value.
if you want textview to take 75% of cardview with textsize 20sp then text will spilt into multiple lines.
android:maxLines="1"
android:singleLine="true"
remove these properties there is no need and allow textview for multiline
Will the text always be the same? If so the solution is pretty simple.
int ratio = 15;
int width = difficultyCardView.getWidth();
diffNameTv.setTextSize(width/ratio);
Adjust the ratio till the size is where you want it, then the text will be the same relative size compared to the card no matter what the screen size is.
What you want to do is to create a responsive layout. To do so create additional layout folders in the res directory. Add the pixel density name at the end of the folder name, separating the text "layout" and the density using a dash (e.g. layout-hdpi, layout-mhdpi, layout-xhdpi etc.) Within these folders, create the layout you want for each density. You can then resize the textview to 75% of each of the different screen sizes based on the pixel density. Therefore if 20sp fills 75% of the hdpi layout then you might need to increase the text size for a the mhdpi to fill 75% of the card.
Android will automatically select the correct layout for a particular device based on the screen size.
<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 have ready many, many tutorials, I have read http://developer.android.com/guide/practices/screens_support.html for the 3rd time, but I still don't know how to set layouts to be compatible for multiple screens.
On android docs I found this:
For instance, a view with a layout_width="100dp" measures 100 pixels
wide on medium-density screen and the system scales it up to 150
pixels wide on high-density screen, so that the view occupies
approximately the same physical space on the screen.
Ok, let's see an example:
As you can see, the resolution is the same (480x800), however the view does not fill till end. I know I should use fill_parent, or match_parent, but this is for test purpose only.
XML Layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:weightSum="100"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="320dp"
android:layout_height="0dp"
android:layout_weight="45"
android:background="#drawable/bg_red" >
</RelativeLayout>
<RelativeLayout
android:layout_weight="10"
android:layout_width="fill_parent"
android:layout_height="0dp" >
</RelativeLayout>
<RelativeLayout
android:layout_width="320dp"
android:layout_height="0dp"
android:layout_weight="45"
android:background="#drawable/bg_blue" >
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
Dp or dip (density-independent pixels) takes the device's density into account. The purpose of density-independent pixels is to display a view in the same physical dimensions on screens of any density.
How many actual pixels a dip equals depends on your device's density:
If you have an mdpi device, one dpi equals one pixel (factor = 1)
On a hdpi device, one dpi is two pixels, which should be
approximately as big in physical size as the one pixel on mdpi. (factor = 2)
It all gets a bit clearer on an actual device:
Your 480*800 hdpi device would be smaller in physical size than the 480*800 mdpi device. Thus, when a view fills the hdpi device's screen, a view with the same physical size (dp) won't fill the screen on your mdpi device.
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.