LinearLayout weights - android

I have two linear layouts that have the same width - one with two children and one with three. I'm trying to make the last two children the same width but I can't wrap my head around why Android behaves this way. I finally got it to look the way I want it to with the following weights:
Can anyone explain to me why this is working out this way?
I tried to do some simple math to figure out why. I'm guessing it's the sum of weights, minus the weight of the child, divided by the sum of weights, times the width of the parent. So:
sum = 1 + 6
((sum - 6) / sum) * W = 14.3% * W
I tried the same algorithm for the second row but it was totally off:
sum = 1 + 1 + 1.5
((sum - 1.5) / sum) * W = 57.1% * W
UPDATE
The above is true only when the child widths are set to match_parent. Setting width to 0, or 0dp, actually behaves as expected - greater weights lead to more space allocated for the child. The algorithm makes a little more sense now and works as expected for both rows.
sum = 1 + 6
(1 / sum) * W = 14.3% * W
Is the former behavior for weights with child widths set to match_parent by design? If so, what is the approximate algorithm for calculating the width of the children?

You can specify weightSum attribute for your LinearLayout in XML to let's say 1 for your first layout. Then your first 2 TextViews would get approx 0.9 and 0.1 weights (like 90% and 10%)
The same thing needs to be applied to the second LinearLayout. Something like:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:weightSum="1"
android:background="#FF0000FF" >
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight=".9"
android:layout_margin="3dp"
android:background="#FFFFFFFF"
android:text="TextView" />
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:layout_margin="3dp"
android:background="#FFFFFFFF"
android:text="TextView" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:weightSum="1"
android:background="#FF0000FF" >
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_margin="3dp"
android:layout_weight=".45"
android:background="#FFFFFFFF"
android:text="TextView" />
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight=".45"
android:layout_margin="3dp"
android:background="#FFFFFFFF"
android:text="TextView" />
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight=".1"
android:layout_margin="3dp"
android:background="#FFFFFFFF"
android:text="TextView" />
</LinearLayout>
BTW, don't forget to set your width attributes to 0dip

First:
Based on the look of your layout, it looks like you'd want to use a GridLayout instead of two LinearLayouts.
Back to your question:
Don't set our layout_width to wrap_content (and especially not match_parent!) in your case.
Set the layout_width to 0dp and let the layout_weight attribute distribute the available horzontal space.
The layout_weight attribute distributes/adds additional space to the specified layout_width (or layout_height for vertical oriented LinearLayouts). If you want only the layout_weight to contribute to the spacing, set layout_width to 0dp (layout_height to 0dp in case of vertically oriented LinearLayout).
Try this first and see if this behaves more to what you'd like and expect.
Try this example (where the grids are ratio 3:3:1):
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FF0000FF" >
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="6"
android:background="#FFFFFFFF"
android:text="TextView" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#FFFFFFFF"
android:text="TextView" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:background="#FF0000FF" >
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:background="#FFFFFFFF"
android:text="TextView" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="3"
android:background="#FFFFFFFF"
android:text="TextView" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#FFFFFFFF"
android:text="TextView" />
</LinearLayout>

According to your picture - weights are incorrect. E.g first "row": you have set first TextView with weight '1' and second weight is '6' - this means that second TextView will have more space - 6/7 of all layout width and first TextView have only 1/7. To simplify calculations imagine total width as 100(%) and divide them between views according to proportions which you want to give them.

Related

Why can't I add more than 2 elements in my horizontal linear layout in Android?

I am trying to create a ListView for my android app. I created an adapter cell's XML to be used to inflate into the ListView. However I can't fit more than two elements.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:weightSum="100">
<TextView
android:id="#+id/serviceItemId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:layout_marginLeft="16dp"
android:layout_weight="70"
android:text="TextView"
android:layout_marginStart="16dp" />
<TextView
android:id="#+id/serviceName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:layout_marginLeft="16dp"
android:layout_weight="60"
android:text="TextView"
android:layout_marginStart="16dp" />
<TextView
android:id="#+id/serviceDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:layout_marginLeft="16dp"
android:layout_weight="60"
android:text="TextView"
android:layout_marginStart="16dp" />
</LinearLayout>
Remove android:weightSum="100" in the parent
Use android:layout_width="0dp" in the children.
You can check the doc about android:weightSum:
Defines the maximum weight sum. If unspecified, the sum is computed by adding the layout_weight of all of the children. This can be used for instance to give a single child 50% of the total available space by giving it a layout_weight of 0.5 and setting the weightSum to 1.0.
Use:
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:id="#+id/serviceItemId"
android:layout_width="0dp"
android:layout_weight="70"
..>
<TextView
android:layout_width="0dp"
android:layout_weight="60"
../>
<TextView
android:layout_width="0dp"
android:layout_weight="60"
.. />
</LinearLayout>
Here you can find more info about the weight.
It is not important to set android:weightSum and you can use the weight as you prefer.
If you want to realize something like 50%-25%-25% just use:
android:layout_weight="2"
android:layout_weight="1"
android:layout_weight="1"
in response to your comment
(apologies I can't post comments yet, so will leave this explanation here)
"Yes that fixed it. But how do you specify the width each takes since I can't use a scale of 100 anymore?"
you can use layout_weight as such, for your 3 TextViews, if u set them all to layout_weigh = 1
this effectively means that they will all occupy the same amount of space.
lets say that you want the first TextView to be perhaps 2x bigger than the other two TextViews, you can simply set it as such
TV1 , layout_weight =2
TV2 , layout_weight =1
TV3 , layout_weight =1
so instead of big percentages, you can play around with the weights with this understanding.
Hope this helps!
Found a great stackoverflow post on this https://stackoverflow.com/a/4517358/4377908

Can someone explain how this weightsum work? and why

When i check the design for this code. this WeightSum act totally opposite the way i want. when i set my button weightSum for 70 it takes 30 (total weightSum is 100) vise-versa.
<LinearLayout
android:weightSum="100"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:layout_weight="70"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Button" />
<ToggleButton
android:layout_weight="30"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="ToggleButton" />
</LinearLayout>
So android:weightSum defines the maximum weight sum of Layout, and it is calculate total sum of the layout_weight of all the its children views.
Example:- a LinearLayout having 3 Views(Which can be anything). Now you want to show 3 views equally in screen. So need to put layout_weight to views 1 and your weightSum is 3.
<LinearLayout
android:weightSum="100"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<View
android:layout_weight="70"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button" />
<View
android:layout_weight="30"
android:layout_width="fill_parent"
android:layout_height="0dp`enter code here`"
android:text="ToggleButton" />
</LinearLayout>
or You can also put your android:layout_weight in points also like below :-
<LinearLayout
android:weightSum="1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<View
android:layout_weight=".7"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button" />
<View
android:layout_weight=".3"
android:layout_width="fill_parent"
android:layout_height="0dp`enter code here`"
android:text="ToggleButton" />
</LinearLayout>
Remember 3 thing before use android:weightSum :-
set the android:layout_width of the children to "0dp"
set the android:weightSum of the parent (edit: as Jason Moore noticed, this attribute is optional, because by default it is set to
the children's layout_weight sum)
set the android:layout_weight of each child proportionally (e.g. weightSum="5", three children: layout_weight="1", layout_weight="3",
layout_weight="1")
You need set android:layout_width="0dp" of Button and ToggleButton.
you have set children view's width=0 if LinearLayout orientation is horizontal and height = 0 if orientation is vertical
I have made changes to your code, please refer :)
<LinearLayout
android:weightSum="100"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_weight="70"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Button" />
<ToggleButton
android:layout_weight="30"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="ToggleButton" />
</LinearLayout>
It works on percentage basis, When you want to make your views' height and width to occupy certain percentage of its parent then weights is the solution
e.g. if weightSum = 1 children can be of weight_layout .30 and.60. So basically addition of children's' layout_weight should be equals to weightSum of their parent (or less in WRT use cases)
In order to make it work well, as others have pointed, the width (or height, if the LinearLayout orientation was vertical) should be 0 (px or dp, whatever you wish, as it's still 0) for the children that have a weight.
About explanation of how it works, if not all had weight, the remaining one would be spread to them.
In your case, you don't have to set weightSum at all, because you've already set the weight for each of them (70+30 is indeed 100).
What it will do (after the needed changes), is set the first View to have a width that's 30% of the width of the parent, and the second view with 70% of the width of the parent.
based orientation, you should set layout_height or layout_width of parent layout to 0dp for correct behavior of weightsum.

Different column size for a listview in Xamarin

I have a listview and each row is shown after inflating the following view. It is a LinearLayout and it works fine until I give each textview (which is a column in my list) the same size. If I change any of those width I get unexpected results. For example, if I put 0.5 to the first textView (called "test") I was expecting that textView to have much smaller size, but it is opposite. So I tried using 3, but again very unexpected behavior. So if I want the first textView to be much smaller than the other 4, how can I do that?
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="30dp"
android:paddingLeft="5dp"
android:paddingTop="2dp">
<TextView
android:text="Test"
android:layout_width="match_parent"
android:layout_weight="3"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#333333"
android:id="#+id/testView" />
<TextView
android:text="Name"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#333333"
android:id="#+id/nameView" />
<TextView
android:text="Surname"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#333333"
android:id="#+id/surnameView" />
<TextView
android:text="Age"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#333333"
android:id="#+id/ageView" />
<TextView
android:text="Profession"
android:layout_width="match_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#333333"
android:id="#+id/professionView" />
If I change any of those width I get unexpected results.
The reason you get unexpected results is that you set every TextView layout_width property to match_parent. The document said that :
Child views can specify a weight value, and then any remaining space in the view group is assigned to children in the proportion of their declared weight.
We can see that the layout_widt property for every TextView in your layout should set to wrap_content. It means the width of the TextView equal to the original width (android: layout_width =warp_content) plus the proportion of the remaining space. Just like this.

Text being truncated in TextView with width set to wrap_content

I'm trying to create a simple component in my layout, where there are two TextViews horizontally next to each other. The one on the right should start where the one on the left finishes. My code for this is as follows:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#android:color/white"
android:textIsSelectable="false"
android:textSize="25sp" />
<TextView
android:id="#+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textColor="#android:color/white"
android:textSize="20sp" />
</LinearLayout>
I programmatically set the text on each TextView after the view has rendered. However, sometimes the text does not display correctly in the first TextView- I can see that the width has been set correctly, as the second TextView is not next to it, but the text is truncated rather than using the space. If I lock/unlock the device to refresh the screen then the text displays correctly (without the widths of the TextViews changing).
I've tried changing this to use a RelativeLayout, but I see the same issue.
Any ideas?
Although i dont understant what exactly you mean, would suggest you to use weightSum property in the parent view and android:layout_weight in child views. The same allows to put many child views inside a parent view with respect to ratio (like navigation tabs).
for eg :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1" >
<TextView
android:id="#+id/text1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:singleLine="true"
android:textColor="#android:color/white"
android:textIsSelectable="false"
android:textSize="25sp"
android:layout_weight="0.4" /> //60% width
<TextView
android:id="#+id/text2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textColor="#android:color/white"
android:textSize="20sp"
android:layout_weight="0.6" /> //40% width
</LinearLayout>
also, dont forget to put the width if child views as 0dp. as that will result in ignoring the calculations regarding the width of view. or you can set the width of child view as "match_parent" as well. any other property to width will not work. (and if you want half matchparent for both child views set layout_width to 0.5 both views.. ithink thats obvious to note)
Hopw it helps.

Proper way to divide into 4 pieces an android layout

what I want to achieve is, divide the rows layout described in picture below. what should I do to achieve dividing the row into 3 exactly same size and 1 unknown size? X are same size and i dont know and dont want to specify if its not necessary...
EDIT: buttons are on the left , center, and right.
Use a LinearLayout inside a RelativeLayout. Put 3 items inside the LinearLayout and give them the same weight. Put the unknown item to the right of the LinearLayout with the help of RelativeLayout.
Left elements will align themselves according to the right-one's width.
Here's the code: https://gist.github.com/3772838
And here 2 screenshots with different sized right most elements:
http://goo.gl/Nezmn
http://goo.gl/XbQwL
Kolay gelsin =)
You can use android:layout_weight to distribute extra space proportionally. You want the three left buttons to absorb all the extra width, so the right (fourth) button should have the default weight of 0. Since you also want them to have the same width, the easiest is to assign them a width of 0dp and give them all the same weight:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Does your extreme left size has a minimum width ?
If so, you should use a LinearLayout with horizontal orientation.
It could contains 2 LinearLayout, one which contains 3 Views (your Buttons) with 0 width and with 1 weight each and the other LinearLayout has a minimumWidth set.
Instead of the marginRight, you could specify a width for the first layout.
Ted Hopp get it right ;)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" android:id="#+id/rlayoutParent">
<RelativeLayout
android:layout_width="wrap_content"
android:id="#+id/rlayoutButtons" android:layout_height="wrap_content">
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" android:layout_toRightOf="#+id/button1"/>
<Button
android:id="#+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" android:layout_toRightOf="#+id/button2"/>
</RelativeLayout>
<RelativeLayout
android:id="#+id/rlayoutOther"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_toRightOf="#+id/rlayoutButtons" android:gravity="right">
<Button
android:id="#+id/button4"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Button" />
</RelativeLayout>
</RelativeLayout>
you cab use the layout_weight attribute. give all the x layout the same weight and the question mark a diffrent weight until the screen will devide as u like

Categories

Resources