Horizontal LinearLayout with max width TextView - android

I have a LinearLayout with horizontal orientation and two TextView children. My goal is to have the left TextView expand to fit its text content, but only up to a maximum width (to leave room for the right TextView). The key is I want to be able to express this maximum width in terms of a percentage similar to the way layout_weight is specified.
The problem with setting the layout_weight is that the TextView is then unconditionally expanded to fill the maximum width, even if the contents don't require the extra space.
Here's my current layout:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:id="#+id/subject"
android:textSize="18sp"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="0.8"/>
<TextView android:id="#+id/date"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

Setting a weight to one view only will only expand it to fill the space. If you want it to be relative you have to give the other view also weight in the layout.

Related

LinearLayout clipping children with TextView width set to wrap_content

I have a LinearLayout which contains a TextView and an ImageView. The TextView width is set to wrap_content, but the issue is when the width reaches the parent width. The text content will correctly wrap to 2 or more lines, but the TextView and ImageView will be clipped on the left and right sides. The most similar question I could find was this one, which is from 2013 and has no solution.
Specifically, I'm experiencing the issue on this view, but I've created the following simpler view to exemplify the problem:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_top_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="#+id/card_top_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="One Two Three Four Five"
android:textSize="40sp"/>
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="#drawable/ic_volume_up_black_48dp"/>
</LinearLayout>
Here is the problem:
Here is the layout normally:
When the layout overlaps another view, setting android:clipChildren="false" on the LinearLayout doesn't even prevent the clipping.
And here is one final image to prove it's happening on a real device and not just the layout viewer:
I'm basically out of ideas. Any thoughts? Is this an issue with the Android layout system? Thanks for the help and consideration!
You can achieve the desired result using android:layout_weight
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/card_top_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="#+id/card_top_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="One Two Three Four Five"
android:textSize="40sp"/>
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="#drawable/ic_volume_up_black_48dp"/>
</LinearLayout>
Edit: A little quote from the docs about how layout_weight works
LinearLayout also supports assigning a weight to individual children with the android:layout_weight attribute. This attribute assigns an "importance" value to a view in terms of how much space it should occupy on the screen. A larger weight value allows it to expand to fill any remaining space in the parent view. 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. Default weight is zero.
For example, if there are three text fields and two of them declare a weight of 1, while the other is given no weight, the third text field without weight will not grow and will only occupy the area required by its content. The other two will expand equally to fill the space remaining after all three fields are measured. If the third field is then given a weight of 2 (instead of 0), then it is now declared more important than both the others, so it gets half the total remaining space, while the first two share the rest equally.

Android Layout weight

I wanted to represent a table. I have a parent container in a LinearLayout with vertical orientation and each row is further represented by a LinearLayout with horizontal orientation & weight of 100. I have used weight to ensure that the left side column and right side columns get 50% of screen width. But the columns on the right side are not properly aligned for some rows. What can I do to properly align them as in a table?
This is how my code appears for each LinearLayout row represented below
<LinearLayout
android:orientation="horizontal"
android:weightSum="100"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_weight="50"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="BOM ID"
android:id="#+id/tvBOMID" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/etBOMID"
android:hint="BOM ID"
android:layout_weight="50" />
</LinearLayout>
Simply give 1-1 equal weight to TextView,EditText and set width as 0dp :
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="BOM ID"
android:id="#+id/tvBOMID" />
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/etBOMID"
android:hint="BOM ID"
android:layout_weight="1" />
</LinearLayout>
To fix this, change the layout_width's to 0dp for the Layouts with weights, everything else looks fine. Any time you use a weight, set the width or height (whichever one is determined by the weight) to 0dp.
in Android we have veryy good concept of Weight.
we give Weight To only in LinearLayout.
and We give Weight To the Layout Horizontally as well as vertical means in simple way we give weight layout height and Width.
in Weight You want To give a 0dp for the height or width which you want to give a weight.if you not give 0dp than its not affect to layout.
Widht wise Weight...
give 1 1 weight so textview takes 50 %and edittext 50% of total width of parent layout.
give 1 2 weight so textview takes 33.33% and editext takes 66.66% total width of parent layout.
give 1 3 weight so textview takes 25% and edittext takes 75% total width of parent layout.
Height wise Weight....
give 1 1 weight so textview takes 50% and edittext 50% of total Height of parent layout.
give 1 2 weight so textview takes 33.33% and editext takes 66.66% total Height of parent layout.
give 1 3 weight so textview takes 25% and edittext takes 75% total Height of parent layout.
in your case You want Width 0dp and weight is 1.
**You just add this code**
android:layout_weight="1"
android:layout_width="0dp"
below the code
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="BOM ID"
android:id="#+id/tvBOMID" />
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="#+id/etBOMID"
android:hint="BOM ID"
android:layout_weight="1" />
</LinearLayout>
just change :
android:layout_width="wrap_content"
to :
android:layout_width="fill_parent"
in textview and edittext.

match_parent not performing as expected

I imagine this should be a fairly easy one to answer, if you understand XML Layouts better than I do that is. I don't seem to get what I was thinking I should when using the match_parent layout_height.
I have a LinearLayout root element with android:orientation="vertical". Inside this LinearLayout I want three elements:
- TextView
- ListView
- TextView
For both the TextViews I set android:layout_height="wrap_content" so that they will be only as tall as is necessary to display their contents. The thing is, I want the one TextView to sit at the top of the form, the other one to sit at the bottom of the form while the ListView fills up whatever space is available on the form. So here is what my xml layout looks like:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="Top TextView" />
<ListView
android:id="#+id/listView_Species"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="Bottom TextView" />
But it doesn't work. Here's what I get. I've selected the ListView so that it will be highlighted. Notice how it extends all the way to the bottom of the form, pushing the bottom TextView off the form.
When I change the layout_height property of the ListView to some fixed value, like 180dp, this is what the form looks like. I'm just posting this to prove that the bottom TextView is there but I still don't know how to get it to be fixed to the bottom of the screen while the ListView takes up whatever space remains, but in between the two TextViews.
Thanks in advance.
While the other answers try to fix your problem (which they don't actually--they suggest you do something that looks similar but may or may not look good on different devices), no one has filled in the gaps in your knowledge of LinearLayouts and match_parent. And these gaps are very common--Google's documentation is still far below stellar.
First, how do Views work within a LinearLayout? Let's go through the process of drawing a LinearLayout, using orientation="vertical" for simplicity.
Examine the height of the first child of the LinearLayout (LL for short). If the height is match_parent or fill_parent (old name for the same thing) then the height of the View is stretched to fill the entire viewing area. If the height is wrap_content, then measure the vertical space the View takes and use that space for the View. If the height is a non-zero number, use exactly that many pixels for the View's height (may clip if too small). If the height is 0 see below.
Put the next view below the view in 1. Check its height and act accordingly.
Continue for all the Views. If a View is pushed off the bottom, go ahead and stop calculating because no one will see it or any succeeding Views (assuming no ScrollView).
If the height of a View is 0, check it's gravity. This requires a second pass, storing the gravity of all the views and then allocating their heights proportionally. As you can guess, the second pass doubles the time layout takes, which isn't significant for simple layouts.
Explanation of your example: The first child of the LL (the first TextView) is measured and takes a certain amount of pixels. Then your ListView takes all the remaining space (via match_parent). And then your second TextView is not drawn at all as it's off the bottom of the screen. Which is pretty much what you observed, but now you understand why.
Solution: Use RelativeLayout. Works perfectly in this case.
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="#+id/top_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:textSize="30sp"
android:text="Top TextView" />
<TextView
android:id="#+id/bottom_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:textSize="30sp"
android:text="Bottom TextView" />
<ListView
android:id="#+id/listView_Species"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/top_tv"
android:layout_above="#id/bottom_tv"
/>
</RelativeLayout>
The RelativeLayout tells the layout inflater to draw the first TextView at the top, then draw the second TextView at the bottom, and then fill the rest of the space with your ListView. I believe this is exactly what you want.
Welcome to Android. You'll be using this pattern a LOT!
Change the ListView height to 0dp and add weight=1
i.e.:
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="Top TextView" />
<ListView
android:id="#+id/listView_Species"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="Bottom TextView" />
use android:layout_weight to define weights to your widgets inside the outermost layout. Declare their height as 0dp and then define android:layout_weight to each one of them .
Total weigh sum of the three of them should be 1. According to your need you can deine 0.1 weight to both top and bottom TextView's and define 0.8 to ListView.
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight = "0.1"
android:textSize="30sp"
android:text="Top TextView" />
<ListView
android:id="#+id/listView_Species"
android:layout_width="match_parent"
android:layout_weight = "0.8"
android:layout_height="0dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:textSize="30sp"
android:layout_weight = "0.1"
android:text="Bottom TextView" />

android:gravity="top" doesn't align child view to top, but "center" aligns to center?

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="top" <!--this line-->
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textSize="56dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:textSize="36dp" />
</LinearLayout>
Shouldn't that make the smaller "0" t-view align to the top of the inner LinearLayout?
Since the other "0" is larger in height, it increases the overall height of the inner LinearLayout.
Alternatively, if you included this:
android:layout_gravity="top"
within the t-view of the smaller 0, it also does nothing.
Why is this?
Does the wrap_content of the LinearLayout wrap each individual view independent of others?
If so, then why does setting gravity to "center" work? In the sense that the smaller zero is vertically centered to its parent.
I know you can just set the smaller 0's height to match parent and set its own gravity to top. I'm just trying to understand this. Thanks.
The default behavior of the layout is to align the baselines of the text, which in English are at the bottom of the view. Adding android:baselineAligned="false" to your LinearLayout will align the second TextView at the top of the view.
gravity attribute applies to widgets within the LinearLayout, while layout_gravity tells the parent of LinearLayout where to place the child (LinearLayout).
Also, in a vertical LinearLayout the gravity="top" attribute won't work.
In the layout you have now, both text views will be stacked one on top of the other, wrapped with a linear layout with no space in-between - so the "top" or "center" values won't do anything because there is no extra space to move the text views up or down.
If you want to understand this better, try giving your linear layout and both text views backgrounds of different colors, like this:
android:background="#color/mycolor"
Then you will see the bounds of each widget.
You can use android:layout_weight="10" and distribute on the other components.

How does android:layout_weight work?

When I have the following, it shows top layout with four colors has much smaller area than the bottom layout area.
According to this documentation, when you add more to layout_weight, it should increase the area, but it decreases in the code.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="4">
<TextView
android:text="red"
android:gravity="center_horizontal"
android:background="#aa0000"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="3"/>
<TextView
android:text="green"
android:gravity="center_horizontal"
android:background="#00aa00"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"/>
<TextView
android:text="blue"
android:gravity="center_horizontal"
android:background="#0000aa"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"/>
<TextView
android:text="yellow"
android:gravity="center_horizontal"
android:background="#aaaa00"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1">
<TextView
android:text="row one"
android:textSize="15pt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:text="row two"
android:textSize="15pt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:text="row three"
android:textSize="15pt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<TextView
android:text="row four"
android:textSize="15pt"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
</LinearLayout>
I had the same problem. The trick is not to use "wrap_content" or "fill_parent" for the controls you are setting a weight to. Instead set the layout_height to 0px (when inside a vertical layout) and then the child controls will get proportioned per the weight values.
If you get the error as
error
Suspicious size: this will make the view invisible, probably intended
for layout ...
remember to set the correct parameter on
android:orientation in parent
If you are using fill_parent in a LinearLayout the layout will take as much space as possible and all layout items defined later will have to deal with the space left.
If you set the height of both of you LinearLayouts to wrap_content the weight should work as documented.
I know this is late but hopefully it helps people:
Use android:weightSum on the parent. Here is a link to the dev docs.
http://developer.android.com/reference/android/widget/LinearLayout.html#attr_android:weightSum
Use android:weightSum of 1.0 on the parent and then use 0.x on the child views with android:layout_weight in order for them to use that ratio of space.
Building on what Janusz said, if you use fill_parent, you can then set android:layout_weight to "split" the "full area" between multiple layout items.
The layout_weight doesn't increase the area, it increases it "right" to the area. but it's also relative to the parent. If you have a parent with a layout_height=fill_parent, with a layout_weight=0 and the parent has a sibling with the same, setting layout_weight=1 to one of the children does not affect the parent.
Both the parent, and the sibling, would take up 50% of the available area that they can fill.
The solution is to set layout_height to 0px when you use layout_weight.
But why do you observe this apparently strange/inversed behavior ?
Shortly : the remaining space is negative and so the child with weight 4 receive more negative space and it's height is more reduced.
Details :
Assume that the height of your parent vertical layout is 100 pixels.
Layout height on each child is fill_parent (i.e. each child is also 100 pixels height)
The total height of all child = 2*100 pixels
The remaining height = 100 - (2*100) = -100 pixels (it is negative)
Now, let's distribute this remaining height between child. The first one will receive the biggest part : 80% (i.e. -100*4/(4+1)). The second child receive 20% (i.e. -100*1/(4+1))
Now compute the resulting height :
child 1 : 100 + (-80) = 20px
child 2 : 100 + (-20) = 80px
Nothing strange here, only mathematics. Just be aware that remaining space can be negative ! (or set the height explicitly at 0 as it is recommended)
In linear layout properties change the layout width to "fill_parent" instead of "wrap_content"
hope it helps.
If the orientation of linearlayout is vertical,then set layout_height as 0dp. In case of horizontal layout set layout_width as 0dp.
If we do not follow above rules,the view tends to take up space as per specified attributes and hence the alignment is not as per expectation.

Categories

Resources