XML Layout weight not working in a ScrollView on android API23 - android

I am doing an Android project in AndroidStudio where a ScrollView contains a vertical LinearLayout and within that LinearLayout there is an ImageView and another LinearLayout. I am trying to set the ImageView to be 10 times smaller than the LinearLayout, the result is showing up correct in the Preview window but not on my phone (Xperia Z3 with API23).
This is what I see in the preview window and what I want to achieve
But on my phone the image fills the width of the screen and the image height is proportional to the original image(almost fills half the screen, so far from what it should be according to the weights)
The app worked like it is supposed to on a Google Pixel 7.1.1 with API25.
Here is a part of the code:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:fillViewport="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_weight="1"
android:adjustViewBounds="true"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:id="#+id/image"
android:scaleType="fitCenter"
android:src="#drawable/bjj2" />
<LinearLayout
android:layout_weight="10"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp">
<LinearLayout
...rest of the app
</LinearLayout>
</LinearLayout>
</ScrollView>
Here is the full code https://github.com/IvarsGoldingen/Bjjscorekeeper/blob/master/app/src/main/res/layout/activity_main.xml
Can someone please tell me what I'm doing wrong.

One should understand how dimensions are calculated.
Let's look one by one.
1) ScrollView is fill_parent/fill_parent (actually one can change this to match_parent/match_parent as fill_parent is deprecated as far as I remember, but it doesn't matter in this case).
So, ScrollView is shown fits whole screen (width and height).
2) LinearLayout inside ScrollView is match_parent/wrap_content. And that is correct. One should use wrap_content for views that inside ScrollView.
The reason why - is that ScrollView is used to wrap long views with usually unknown height (like lists). Imagine here match_parent as height - height of LinearLayout would be calculated based on height of scroll view, which is whole screen height, and LinearLayout height can be greater that screen height. Just not logical. But everything is OK till now. Move on.
3) Items inside LinearLayout. You want them to be 1/10 and 9/10 of height of parent layout. Also, you set height for inner items to 0 to show that you want height to be calculated from weights.
And here you got a cycle of dependencies. LinearLayout height is wrap_content and depends on sum of heights of inner elements.
And inner elements' height is calculated from parent LinearLayout height.
Additionally, you want ImageView to be 1/10 of the LinearLayout height. But actually seems like you want ImageView to be 1/10 of the screen's height, as LinearLayout height can be greater than screen's height (and looks like this is what you get on your device).
You say, that everything is OK in preview in Android Studio.
To demonstrate that not everything is OK try this:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/activity_main"
android:fillViewport="true"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_weight="1"
android:adjustViewBounds="true"
android:layout_height="0dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:id="#+id/image"
android:scaleType="fitCenter"
android:src="#drawable/bjj2" />
<LinearLayout
android:layout_weight="10"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp">
<View
android:layout_width="match_parent"
android:layout_height="1000dp"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
Just put some big (bigger than screen's height) view inside your inner-inner LinearLayout and you will see that in preview your image is bigger than 1/10 of screen's height. But it is 1/10 of LinearLayout's height.
How to solve your issue?
I think the only way is to calculate 1/10 of the screen's height and resize bitmap with image you want to have and set that bitmap to ImageView.
Or any other way to set exact height to ImageView.
Or review your layout and create something different.

we can set height of the image view at run time by avoiding layout_weight using display metrics .
e.g
DisplayMetrics displayMetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int height = displayMetrics.heightPixels;
int width = displayMetrics.widthPixels;
yourImageView.getLayoutParams().height = height / 5;
yourImageView.getLayoutParams().width = width / 4;

Related

Let Linearlayout width be 650dp if parent is over 650dp, otherwise match parent

I'm creating a LinearLayout inside a FrameLayout, the LinearLayout needs to be centered inside FrameLayout, but the width of LinearLayout needs to change as follows:
If parent FrameLayout is over 650dp, then set LinearLayout width to 650dp, this leaves some margin at left and right of linear layout.
If parent FrameLayout is under 650dp, then set Lineralyout width to match parent.
Parent FrameLayout width will change on orientation change, I tried to use OnLayoutChangeListener, OnGlobalLayoutListener, OnAttachStateChangeListenerto detect the width after screen rotates, but none of them works.
Am I on the right track by trying to find the width of parent view?
Or is it possible to use parent view as ConstraintLayout and make the LinearLayout inside comply 650 when possible and expand to parent when width is not enough?
(Note I can't use different values under different layout res folders like sw600 or sw600-land, as the parentview is not necessarily occupying the entire screen, it might just be one of the two columns on the screen)
The appropriate way to handle this is to create another layout file under layout-land and use a 650dp width for that. And for more description on supporting different screens see the official training here.
For any one interested, I solved it with a ConstraintLayout per Eugen's comment. This will make sure the LinearLayout's width matches parent on smaller screens(<650dp) and cap the width to 650dp on bigger screen sizes
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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="wrap_content">
<LinearLayout
android:id="#+id/row_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_max="650dp"/>
</android.support.constraint.ConstraintLayout>
<LinearLayout
android:layout_width="300dp"
android:layout_height="100dp"
android:background="#f00"
>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:maxWidth="200dp"
android:minWidth="200dp"
android:background="#00f"
>
</LinearLayout>
</LinearLayout>
Result when parent width = 150dp

How to set height proportional to width according to device dpi in android

I would like to fix the height of imageview but according to different devices and dpi's.
<ImageView
android:id="#+id/imgFood"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop"
android:src="#drawable/ic_no_img" />
As of now I fixed the height to 200dp, but I want to keep it ratio of 1:2 instead of fix size. I know android works on dp but I am unable to figure out how can i keep the ratio for all devices. Width will be match parent (fit device width) but height needs to be changed accordingly.
Any idea/suggestion?
You can set your height dynamically like this.
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
ll.getLayoutParams().height = width/2;
ll.getLayoutParams().width = width;
ll.requestLayout();
You can set height or width ratio of views inside LinearLayout using the layout_weight property, for example:
<LinearLayout
android:weightSum="3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<View
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<View
android:layout_weight="2"
android:layout_width="0dp"
android:layout_height="wrap_content" />
</LinearLayout>
This will cause the inner Views of the LinearLayout to take one and two thirds of its width, respectively.
Otherwise, if you have to use a different layout, there is currently no way to do this in .xml files, and the option is to fall back to setting the size programmatically, like in Hussnain Azam's answer (you don't always have to call for size of the display though).

Android layout Height and width

I use match_parent for height,but I don't want to use wrap_content or fill_parent for width. I want to set height as same as width. How can I do that in layout.xml?
Your question largely depends on whether you are in portrait or landscape.
If you are trying to make a layout width to match the height in portrait, then your layout will be going off screen, which does not seem possible in xml. And vice-versa, matching the height to the width in landscape would make the layout go offscreen as well.
If you are trying to make a square layout the same dimension as the smallest dimension of the screen, then a round about way to do that in xml is to make a shape drawable that is square, transparent and larger than your screen size. Then set the drawable to be an imageview inside a relativelayout and set your width and heights to the proper settings (match_parent or wrap_content). Then add views to the relativelayout as needed and reference them to the parent and not the image, making the new views reside "on top" of the imageview.
In portrait, the following relativelayout is square:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:src="#drawable/square_draw" />
</RelativeLayout>
</LinearLayout>
In landscape, the following relativelayout is square:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#android:color/white"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:src="#drawable/square_draw" />
</RelativeLayout>
</LinearLayout>
Also, make sure that adjustViewBounds is set to true. For some reason, this solution does not allow the image to grow larger than the screen size and it also uses more resources due to the overdraw.

How to make 2 images views each be sized to cover screen inside a linear layout inside a horizontal scrollview

I'm trying to get 2 (or more as needed) imageviews inside a linearlayout inside a horizontalscrollview, such that each image is scaled to fit the screen height without distorting the image ie one image showing as large as possible on screen, scroll to see next one.
once the second image is added, i get 2 small images next to each other (dimensions are 217 * 300px for both images). currently my activity_main.xml looks like the following..
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:orientation="horizontal"
android:layout_width="wrap_content"
android:layout_height="match_parent"
>
<ImageView
android:id="#+id/image1"
android:src="#drawable/luke"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
/>
<ImageView
android:id="#+id/image2"
android:src="#drawable/luke"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"
/>
</LinearLayout>
</HorizontalScrollView>
</FrameLayout>
I've tried various combinations of match_parent, fill_parent, wrap_content on the layouts, all the scaleTypes on the image views and spent over a day browsing the net looking for an example similar to what i want, but no luck.
I would say to set these two things:
<ImageView
android:layout_height = "match_parent"
android:layout_width = "10dp" />
This is the tricky part. Get the screen width at runtime, and set it to the imageView.
I'd be inclined to use a viewpager with a custom page adapter showing your scaled imageview instead of trying to do it in way you are currently.
The view pager / adapter would handle view recyling, page snapping etc for you.
how about using
android:width="0"
android:weight ="1"
android:height="match_parent"
In the imageViews
and match_parent else where in your layout.

wrap_content for ListView height and width

I would like to restrict the height and width of a ListView, wrapping the height based on the number of children's and wrapping the width based on width of list view row.
So far, I have been able to restrict the height of the ListView. The code I'm using for restricting height is:
listview.setLayoutParams(new linealayout.layoutparams(LayoutParams.WRAP_CONTENT, 0,1));
How can I also restrict the width?
I hope you should be more specific about your desired screen look/view
But when it comes to listview I would say never use 20,30 dp to set width and height just use weight and wrap_content to make it flexible.
see below code example this may help you
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ListView
android:layout_height="wrap_content"
android:id="#+id/listView1"
android:layout_width="match_parent"
android:layout_weight="1"></ListView>
<Button
android:text="Button"
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
</LinearLayout>
let me know if you still have any trouble to get this one.

Categories

Resources