Horizontally center Views inside Android GridLayout - android

We are writing an app targeting ICS+ and believe a GridLayout is the best layout paradigm, but it seems very little has been written about it, and we are having some alignment issues.
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/row_background"
android:rowCount="1"
android:columnCount="3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:useDefaultMargins="true"
android:background="#drawable/list_item_bg">
<ImageView
android:id="#+id/visibilityIcon"
android:layout_row="0"
android:layout_column="0"
android:src="#drawable/visibility_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<ImageView
android:id="#+id/windIcon"
android:layout_row="0"
android:layout_column="1"
android:src="#drawable/wind_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
<ImageView
android:id="#+id/crosswindIcon"
android:layout_row="0"
android:layout_column="2"
android:src="#drawable/cloud_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"/>
</GridLayout>
However, the left 2 icons remain left-aligned, and the right-most icon centers with the remaining space.
Essentially what we need to do is specify the size of each column to be 1/3 (since 3 columns) of the total screen size. I thought this is what GridLayout did, but it appears 'wrap_content' causes this behavior (makes sense), but 'match_parent' causes the first column to fill the entire screen, rather than fill its cell which is the behavior I would have expected.
We seem to have tried every combination of gravity, layout_gravity, etc., but either we fundamentally are doing something wrong, or have found a limitation of the GridLayout.
Thanks for your help!

Only one row and one column is allowed to grow in a GridLayout, and that is the one with gravity along that axis. If more than one row or column specify gravity only one will get it (if I remember it is the "last" one). Choose another layout or write your own. If you only want a row with equally split icons you can use a LinearLayout where the widths of the components are 0px and the weight are all the same, e.g. 1.

Related

RelativeLayout - can't make views the same vertical size if they are horizontally aligned

I have a layout which has two CardView's and looks like this:
I wanted the right card to be fixed width (90dp) and the left one to automatically resize and fill the remaining space. I have currently done it like this:
<RelativeLayout
android:id="#+id/inventory_host_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true">
<android.support.v7.widget.CardView
android:id="#+id/inventory_last_scanned_wrapper_card"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:layout_toLeftOf="#+id/inventory_scanned_infobox_wrapper_card">
...
</android.support.v7.widget.CardView>
<android.support.v7.widget.CardView
android:id="#+id/inventory_scanned_infobox_wrapper_card"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_alignParentBottom="false"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_centerVertical="false"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp">
...
</android.support.v7.widget.CardView>
</RelativeLayout>
Left one can grow, so I also wanted the right card to always be the same height as the left one. Usually I do that kind of alignment by setting both layout_alignTop and layout_alignBottom properties to other View but those properties are not available this time, probably because that would create a circular reference (although I don't really understand how horizontal alignment could affect vertical). What to do? I have explored several other options but always get back to the same point except hardcoding heights or setting them programmatically which of course I want to avoid.
Where and why are you getting circular reference errors? Just set
android:layout_alignBottom="#id/inventory_last_scanned_wrapper_card"
on the card at the right side and everything should work.

Android RelativeLayout: Rightmost child takes all the extra space no matter what I do

I have a RelativeLayout with three child views laid out horizontally. I want the leftmost one to take up any extra space and the other two to take up only the space needed to wrap their content. The documentation says this can be done, but I can't make it work. Here's what I have:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="6dp"
android:textStyle="bold"
android:layoutDirection="rtl">
<TextView
android:id="#+id/nodeLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="#dimen/text_size"
android:gravity="fill_horizontal"
android:layout_alignParentLeft="true" />
<Button
android:id="#+id/launch"
android:text="#string/launch_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/nodeLabel"
android:gravity="left" />
<Button
android:id="#+id/kill"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/launch"
android:layout_alignParentRight="true"
android:text="#string/kill_label"
android:gravity="left" />
</RelativeLayout>
The result is the TextView takes up all the space, and the two Buttons are not rendered at all. If I change android:layout_width on the TextView from match_parent to wrap_content, then all three Views show up, but the third one, the Button, takes the extra space, which is not what I want. I also tried setting layout_width on the Buttons to 0dp, and experimented with other settings values, all to no avail.
How can I make the two Buttons no bigger than needed to wrap their content, and have the TextView take up the extra space?
add the propery android:layout_weight="x".
It works like this:
if there are 4 views in a row and every one has a weight of 1. Then every view occupies 1/4 of the space. If one has a weight of 2 then it occupies 2/5 and so on. If one has a weight of 0 or no weight, then it just occupies as much space as its content does. The system adds all the weights together and then sets every view the proportional width.
In your case you have to weigh them something like 1, 0, 0.

How to mimic RelativeLayout params in GridLayout

I am trying to rework one of my layouts using GridLayout and a bit stuck with one of the problems. Here is what I have now:
And this is my layout:
<GridLayout
style="#style/Widget.Card"
android:layout_width="match_parent"
android:layout_height="#dimen/card_height"
android:background="#color/news_card_background"
android:clipChildren="false"
android:clipToPadding="false"
android:columnCount="3"
android:rowCount="2" >
<ImageView
android:id="#+id/thumbnail"
android:layout_width="#dimen/card_thumbnail_width"
android:layout_height="match_parent"
android:layout_rowSpan="2"
android:background="#drawable/news_card_thumbnail_background"
android:contentDescription="#string/thumbnail"
android:cropToPadding="true"
android:scaleType="centerCrop"
android:visibility="visible" />
<com.inrix.twc.view.RobotoTextView
android:id="#+id/title"
style="#style/TextAppearenceNewsTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="#dimen/news_title_horizontal_margin"
android:layout_marginRight="#dimen/news_title_horizontal_margin"
android:text="Title" />
<ImageView
android:id="#+id/icon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:layout_rowSpan="2"
android:src="#drawable/audio_mrss"
tools:ignore="ContentDescription" />
<com.inrix.twc.view.RobotoTextView
android:id="#+id/footer"
style="#style/TextAppearenceNewsFooter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginLeft="#dimen/news_description_horizontal_margin"
android:layout_marginRight="#dimen/news_description_horizontal_margin"
android:text="description" />
</GridLayout>
But when one of the text views goes very long, it pushes my last column out of the screen:
The question is - how do I restrict my text to go beyond row's bounds, so my icon always stays right-aligned. So basically I'm trying to mimic RelativeLayout's toLeftOf attribute.
I realize I can easily do that with RelativeLayout, but it doesn't quite work for me because of other reasons. I hope it is possible to do with GridLayout
Thats not the target of gridlayout. I don't think that is even (easily) possible. Blockqoute from GridLayout limitations.
GridLayout does not provide support for the principle of weight, as defined in weight. In general, it is not therefore possible to configure a GridLayout to distribute excess space between multiple components.
Some common use-cases may nevertheless be accommodated as follows. To place equal amounts of space around a component in a cell group; use CENTER alignment (or gravity). For complete control over excess space distribution in a row or column; use a LinearLayout subview to hold the components in the associated cell group. When using either of these techniques, bear in mind that cell groups may be defined to overlap.
TextView needs weight to define his own size on the screen (using wrap content).
You can try to use relative layout or build a tree of linearlayout like this:
LinearLayout horizontal
ImageView #thumbnail
LinearLayout vertical weight 1
TextView #title
TextView #footer
ImageView #icon

XML Layout Alternative (mine gets a Lint warning)

I have a ListView in which each row is a GridLayout with two rows. I want each list item to be at least 48dp high (recommended minimum size for press targets) because each can be pressed, and I want the GridLayout to be vertically centered in the row if it doesn't expand it.
To do this, I've put the GridLayout inside a FrameLayout, set the FrameLayout to a minimum height of 48dp, and set the layout_gravity of the GridLayout to center. If I don't use the FrameLayout and just set the minimum height of the GridLayout, then I can't get the whole thing nicely vertically centered because of GridLayout's bogus space distribution.
So, using the FrameLayout gives me the desired outcome, but generates a Lint warning in my XML file, "This GridLayout layout or its FrameLayout parent is useless." Obviously it's not useless since it lines stuff up right, but is there a better way to do it that I missed?
Here is my XML (I cut out a bunch of TextViews in the GridLayout because they're not relevant to this situation):
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="48dp"
>
<GridLayout
android:layout_gravity="center"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
android:rowCount="2"
android:useDefaultMargins="true"
>
<TextView android:id="#+id/number"
android:layout_gravity="center_vertical"
android:layout_marginLeft="2dp"
android:layout_rowSpan="2"
android:minEms="1"
/>
<TextView android:id="#+id/a"
android:layout_gravity="center_vertical"
android:layout_rowSpan="2"
android:minEms="2"
/>
<TextView android:id="#+id/b"
android:layout_marginBottom="0dp"
android:minEms="3"
/>
<TextView android:id="#+id/c"
android:layout_marginTop="0dp"
android:minEms="3"
/>
...
</GridLayout>
</FrameLayout>
Unless you're seeing a performance problem, I'd just keep it that way. If you're seeing a performance problem, and it's because of the additional FrameLayout (you can tell that if the problem goes away if you use GridLayout directly), then (and only then) I'd try fixing the GridLayout directly.
If that's the case, then what I know is that GridLayout distributes excess space according to the principle of flexibility. If that principle is not enough to disambiguate, then you'd see the behavior where it gives the excess space to the rightmost column and bottom row. I'd try to play with the row/col attributes to make sure that it understands how to distribute that evenly. You can control that by setting the gravity of the children of the GridLayout, in your case the TextViews. Try setting them to 'center', and see if that helps. If not, more info at:
http://developer.android.com/reference/android/widget/GridLayout.html

android layout dynamic sizing

For many "header" TextViews across the pages I'm designing for a program, I would like them to be the parent.Width / 2 then properly aligned. While that would be fairly easy to code in the Java, I am attempting to do as much as possible in the XML layouts to avoid XML-Java code intersections until the last little bits (button presses, finish page, etc).
Do I have to go through each page and calculate every item's specific width myself or is there a way to put something along the lines of "fill_parent / 2"?
EDIT: Forgot to mention what is likely a key note - almost everything I am doing is in RelativeLayouts, I have very little use for LinearLayouts in this project.
If you have a LinearLayout that is flush to the left and right, you can do the following:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="2"
android:gravity="left"
android:orientation="horizontal">
<TextView
android:layout_weight="1"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:text="I take up half the width!!!1" />
</LinearLayout>
By setting the weightSum on the parent, you're saying that the weights of the children should equal that amount. By setting the single child's weight to half of that, it'll take up half the space. Make sure to set the width of the child to 0 so it knows to use the weight value to calculate its space relative to its parent.
Then, you can align it however you'd like by setting gravity on the parent LinearLayout.
Use a tableview with two columns where each column is stretched and has a text view. Then hide the second textview
<TableLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="1">
<TableRow>
<TextView android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" Set Item Name "/>
<TextView android:id="#+id/hiddenTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="invisible"/>
</TableRow>
</TableLayout>

Categories

Resources