Taming Android ListView Height within a TableRow - android

n.b.: I was going to post all this XML on Pastebin but I think it's important to have it archived here for posterity, so please pardon the code sample length! Better to have more info than less, right?
Consider the following calculator-ish layout. (I hard-coded the strings just for this post - they are normally resources.)
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/calculator"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp"
android:orientation="vertical"
android:stretchColumns="*">
<TableRow android:id="#+id/tableRowFieldName"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/textViewFieldName"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:layout_marginTop="0dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="5dp"
android:padding="0dp"
android:text="Label"
android:textSize="20dp"
android:textColor="#FFFFFF"
android:textAppearance="?android:attr/textAppearanceMedium" />
</TableRow>
<TableRow android:id="#+id/tableRowDisplay"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/textViewDisplay"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:layout_margin="5dp"
android:layout_marginTop="0dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="5dp"
android:padding="0dp"
android:text="Value"
android:textSize="35dp"
android:textColor="#FFFFFF"
android:textAppearance="?android:attr/textAppearanceLarge" />
</TableRow>
<TableRow android:id="#+id/tableRow1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="0.2">
<Button android:id="#+id/buttonA"
style="#style/ParameterButton"
android:text="Param A" />
<Button android:id="#+id/buttonB"
style="#style/ParameterButton"
android:text="Param B" />
</TableRow>
<TableRow android:id="#+id/tableRow2"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="0.2">
<Button android:id="#+id/buttonC"
style="#style/ParameterButton"
android:text="Param C" />
<Button android:id="#+id/buttonD"
style="#style/ParameterButton"
android:text="Param D" />
</TableRow>
<TableRow android:id="#+id/tableRow3"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="0.2">
<Button android:id="#+id/buttonE"
style="#style/ParameterButton"
android:text="Param E" />
<Button android:id="#+id/buttonF"
style="#style/ParameterButton"
android:text="Param F" />
</TableRow>
<TableRow android:id="#+id/tableRow4"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="0.4">
<ListView android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="gone"
android:layout_weight="1.0" />
<TableLayout android:id="#+id/calcKeypad"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:stretchColumns="*">
<TableRow
android:layout_weight="0.25"
android:gravity="center">
<Button android:id="#+id/button7"
style="#style/KeypadButton"
android:text="7" />
<Button android:id="#+id/button8"
style="#style/KeypadButton"
android:text="8" />
<Button android:id="#+id/button9"
style="#style/KeypadButton"
android:text="9" />
</TableRow>
<TableRow
android:layout_weight="0.25"
android:gravity="center">
<Button android:id="#+id/button4"
style="#style/KeypadButton"
android:text="4" />
<Button android:id="#+id/button5"
style="#style/KeypadButton"
android:text="5" />
<Button android:id="#+id/button6"
style="#style/KeypadButton"
android:text="6" />
</TableRow>
<TableRow
android:layout_weight="0.25"
android:gravity="center">
<Button android:id="#+id/button1"
style="#style/KeypadButton"
android:text="1" />
<Button android:id="#+id/button2"
style="#style/KeypadButton"
android:text="2" />
<Button android:id="#+id/button3"
style="#style/KeypadButton"
android:text="3" />
</TableRow>
<TableRow
android:layout_weight="0.25"
android:gravity="center">
<Button android:id="#+id/buttonClear"
style="#style/KeypadButton"
android:text="C" />
<Button android:id="#+id/button0"
style="#style/KeypadButton"
android:text="0" />
<Button android:id="#+id/buttonDecimal"
style="#style/KeypadButton"
android:text="." />
</TableRow>
</TableLayout>
<LinearLayout android:id="#+id/linearLayoutTotal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<Button android:id="#+id/buttonTotalWeight"
style="#style/FunctionButton"
android:text="Function A" />
<Button android:id="#+id/buttonTotalCost"
style="#style/FunctionButton"
android:text="Function B" />
<Button android:id="#+id/buttonAbout"
style="#style/FunctionButton"
android:layout_height="0dp"
android:layout_weight="0.25"
android:text="Function C" />
</LinearLayout>
</TableRow>
</TableLayout>
This uses the following styles (essentially factored out of the original XML):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CalcButton">
<item name="android:textColor">#ffffff</item>
<item name="android:textSize">15dp</item>
<item name="android:textStyle">bold</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:layout_margin">2dp</item>
</style>
<style name="ParameterButton" parent="CalcButton">
<item name="android:layout_width">0dp</item>
<item name="android:layout_weight">0.5</item>
</style>
<style name="KeypadButton" parent="CalcButton">
<item name="android:textSize">20dp</item>
</style>
<style name="FunctionButton" parent="CalcButton">
<item name="android:layout_height">0dp</item>
<item name="android:layout_weight">0.375</item>
</style>
</resources>
If you were to drop all of this in to an Android project, you should see three rows of two parameter buttons up top, followed by a numeric keypad below that, with three function buttons to the right of the keypad. Mostly harmless. (Also, it will only ever be used in portrait - so no worries about taking landscape into consideration.)
However ... pay particular attention to the ListView within the XML. You won't see it in the visual just yet, since it has android:visibility="gone". The idea is that, at certain times, I will remove that, then set the numeric keypad (the adjacent TableLayout) to have android:visibility="gone" instead, thus showing the list in its place.
Put another way, the desired effect is to have the list and the numeric keypad occupy exactly the same space, such that I can flip back and forth between the two at will.
The problem I'm having is that the ListView, once populated, seems intent on taking up the entire height of the overall table, obliterating the poor parameter buttons and bringing the three function buttons along for the ride.
You can see this by rigging a very basic ArrayAdapter (I used android.R.layout.simple_list_item_1 and android.R.id.text1) and tossing a rudimentary String array its way. For now, manually move the gone assignment from the list over to the adjacent table layout (or do it in code).
Setting a fixed height seems out of the question, since this should be working on a variety of displays. In fact, I even tried what is perhaps a misguided endeavor:
ListView list = (ListView) findViewById(android.R.id.list);
TableLayout calcKeypad = (TableLayout) findViewById(R.id.calcKeypad);
list.layout(calcKeypad.getLeft(), calcKeypad.getTop(), calcKeypad.getRight(), calcKeypad.getBottom());
calcKeypad.setVisibility(View.GONE);
list.setVisibility(View.VISIBLE);
Nope, that didn't help either.
In keeping with the documentation, I've even given ListView the proper ID since I want to customize its layout. Of course I'm not using a ListActivity, so perhaps it doesn't matter in this case. (I'm just using a regular Activity. Yes, I tried changing that to ListActivity too. No dice.)
Still, I'm totally open to this being pilot error. (In fact, I'm counting on it.) I'm just at the point where it's become head-hitting-the-wall-in-myopia mode. "There's got to be a better way!"
Again, keep in mind I'm trying very hard to keep the layout fluid, so that it works well on a variety of display sizes (not tablets, just handhelds), hence the chosen layout. If there's a better way that accomplishes the same visual, I'm all ears.
Bottom line: How do I make the ListView only take up the area occupied by that adjacent calculator keypad (TableLayout)?
Clues/answers/guidance appreciated!

There are some problems in your layout, but I didn't spend a lot of time trying to sort out the various layout_weight and layout_height situations that you have. I think you might be able to get this to work, but I took a little different approach.
I broke the layout up into a series of rows above the three elements at the bottom. Basically you have:
TextView-------------------------------
TextView-------------------------------
LinearLayout---------------------------
LinearLayout---------------------------
LinearLayout---------------------------
---------------------------------------
TableLayout and ListView | LinearLayout
I'm not saying this is the most efficient layout, but every layout element has a job, so you might have to go to some lengths to replace them with something more efficient.
In particular, the use of LinearLayout for your Parameter buttons and Function buttons makes good use of the layout_weight feature. It's not available in other layouts that are not subclasses of LinearLayout (you may not be aware that TableRow is a subclass of LinearLayout, and that's why layout_weight works there but not in RelativeLayout) and the ability to subdivide available space on a percentage basis seems to be appropriate for those elements.
The TableLayout holding the numeric buttons could probably be replaced, but it's doing a good job of allocating space for the buttons in different sized views, and it is also doing a nice job of spacing the rows to fill the available space. Again, it might be difficult to replace this.
What I did was replace your overall TableLayout with a RelativeLayout with appropriate alignment attributes. That allows you to put the Function button LinearLayout against the right border and have the ListView or TableLayout consume the remaining space below the Parameter buttons and to the left of the Function buttons. I'm not saying you have to do this, necessarily, but it saves some extra layout elements over your original design and does the job you are looking for.
Here's a workup of what I did. Notice that I added a layout_height of wrap_content to your ParameterButton style. Also, both the ListView and TableLayout are visible in this layout. You may want adjust in the layout or in your code.
The style:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="CalcButton">
<item name="android:textColor">#ffffff</item>
<item name="android:textSize">15dp</item>
<item name="android:textStyle">bold</item>
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">fill_parent</item>
<item name="android:layout_margin">2dp</item>
</style>
<style name="ParameterButton" parent="CalcButton">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">0dp</item>
<item name="android:layout_weight">0.5</item>
</style>
<style name="KeypadButton" parent="CalcButton">
<item name="android:textSize">20dp</item>
</style>
<style name="FunctionButton" parent="CalcButton">
<item name="android:layout_height">0dp</item>
<item name="android:layout_weight">0.375</item>
</style>
</resources>
The layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/calculator"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp"
android:orientation="vertical"
android:stretchColumns="*">
<TextView android:id="#+id/textViewFieldName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_marginTop="0dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="5dp"
android:padding="0dp"
android:text="Label"
android:textSize="20dp"
android:textColor="#FFFFFF"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView android:id="#+id/textViewDisplay"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1.0"
android:layout_margin="5dp"
android:layout_marginTop="0dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="0dp"
android:layout_marginLeft="5dp"
android:padding="0dp"
android:layout_below="#id/textViewFieldName"
android:text="Value"
android:textSize="35dp"
android:textColor="#FFFFFF"
android:textAppearance="?android:attr/textAppearanceLarge" />
<LinearLayout android:id="#+id/tableRow1"
android:layout_below="#id/textViewDisplay"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:id="#+id/buttonA"
style="#style/ParameterButton"
android:layout_height="wrap_content"
android:text="Param A" />
<Button android:id="#+id/buttonB"
style="#style/ParameterButton"
android:text="Param B" />
</LinearLayout>
<LinearLayout android:id="#+id/tableRow2"
android:layout_below="#id/tableRow1"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:id="#+id/buttonC"
style="#style/ParameterButton"
android:text="Param C" />
<Button android:id="#+id/buttonD"
style="#style/ParameterButton"
android:text="Param D" />
</LinearLayout>
<LinearLayout android:id="#+id/tableRow3"
android:layout_below="#id/tableRow2"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<Button android:id="#+id/buttonE"
style="#style/ParameterButton"
android:text="Param E" />
<Button android:id="#+id/buttonF"
style="#style/ParameterButton"
android:text="Param F" />
</LinearLayout>
<ListView android:id="#android:id/list"
android:layout_below="#id/tableRow3"
android:layout_toLeftOf="#+id/linearLayoutTotal"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<TableLayout android:id="#+id/calcKeypad"
android:layout_below="#id/tableRow3"
android:layout_toLeftOf="#id/linearLayoutTotal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="*">
<TableRow
android:layout_weight="0.25"
android:gravity="center">
<Button android:id="#+id/button7"
style="#style/KeypadButton"
android:text="7" />
<Button android:id="#+id/button8"
style="#style/KeypadButton"
android:text="8" />
<Button android:id="#+id/button9"
style="#style/KeypadButton"
android:text="9" />
</TableRow>
<TableRow
android:layout_weight="0.25"
android:gravity="center">
<Button android:id="#+id/button4"
style="#style/KeypadButton"
android:text="4" />
<Button android:id="#+id/button5"
style="#style/KeypadButton"
android:text="5" />
<Button android:id="#+id/button6"
style="#style/KeypadButton"
android:text="6" />
</TableRow>
<TableRow
android:layout_weight="0.25"
android:gravity="center">
<Button android:id="#+id/button1"
style="#style/KeypadButton"
android:text="1" />
<Button android:id="#+id/button2"
style="#style/KeypadButton"
android:text="2" />
<Button android:id="#+id/button3"
style="#style/KeypadButton"
android:text="3" />
</TableRow>
<TableRow
android:layout_weight="0.25"
android:gravity="center">
<Button android:id="#+id/buttonClear"
style="#style/KeypadButton"
android:text="C" />
<Button android:id="#+id/button0"
style="#style/KeypadButton"
android:text="0" />
<Button android:id="#+id/buttonDecimal"
style="#style/KeypadButton"
android:text="." />
</TableRow>
</TableLayout>
<LinearLayout android:id="#id/linearLayoutTotal"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_below="#id/tableRow3"
android:layout_alignParentRight="true"
android:orientation="vertical">
<Button android:id="#+id/buttonTotalWeight"
style="#style/FunctionButton"
android:text="Function A" />
<Button android:id="#+id/buttonTotalCost"
style="#style/FunctionButton"
android:text="Function B" />
<Button android:id="#+id/buttonAbout"
style="#style/FunctionButton"
android:layout_height="0dp"
android:layout_weight="0.25"
android:text="Function C" />
</LinearLayout>
</RelativeLayout>

The reason is that layout width is set to be fill parent
use wrap content instead and assign weight 1 to both table layout and llistview after placing them under horizontal linear layout

Joe,
There are a number of solutions that can provide the solution that you seek. After looking at your Layout, I am left to wonder why you are using a TableLayout? I mean, at first glance, a calculator is like a Table, kind of. Have you considered other Layout solutions yourself? You certainly mention that others are ok, but the real question is how you have considered them or what you know about them. Because of the lack of information in this regard, I am going to highlight the different kinds of Layouts and their particular strengths. The reason I am addressing it in this way is that most Layout issues result from choosing the wrong layout type.
FrameLayout
This Layout is tricky for some. It is great if you have multiple Views that are the same size. The positioning of the immediate children is always the same (top left of the Frame), regardless of size. The weakness of FrameLayout is that you must manually position children if they are going to be on the screen at the same time. Many developers (wrongfully) stick them inside a container in order to keep positioning.
LinearLayout
One of the most over-used Layouts. LinearLayouts are particularly awesome if you have similarly sized views that must grow the parent linearly. Many, many novice developers use LinearLayout and layout_weight for everything. The issue is that in many cases, things aren't truly growing linearly and layout_weight is relatively inefficient, according to Google itself.
RelativeLayout
A great layout that offers incredibly flexibility with relative positioning. Positioning is based on previously declared view ids or parent attributes. If your positioning is based on sibling properties, this layout is the best to use. It also does not require layout_weight, but allows you to utilize it. The most important thing here is ordering. If your views aren't ordered correctly in your XML then they don't render correctly or error out. Ordering is determined by what views determine your other properties.
TableLayout
Layout that provides a grid/cell like structure for your layouts. Its sizing is entirely dependent upon the parent, and positioning is, in most cases, based upon the previous cell. One of the things many devs learn is that it can be troublesome with hidden Views and cells of different sizes. This is best for displaying data or its interfaces.
Now, for your Solutions
If you are still keen on using the TableLayout, set the visibility of your ListView to "invisible" rather than "gone". The difference between these two is subtle but important. "invisible" means that it still takes up layout even though it is not visible. "gone" means that it loses all of its layout properties and they must be set manually when you show the object.
Given your particular requirements, I think a RelativeLayout would be optimal for positioning. It doesn't require you to use the layout_weight which optimizes the layout and measure passes. And it allows you to size and position according to how other views and layouts are placed on the screen. You simply have to decide what your anchor views are and start there. Then you can place your ListView with layout_below
If you need more information on any of these Layouts, I will gladly provide links for you to the official sources.
Hope this helps,
FuzzicalLogic

Related

FrameLayout height not matching parent

I have the following layout as custom view in AlertDialog.
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:padding="16dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="vertical">
<GridLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:columnCount="3">
<TextView
android:id="#+id/code1"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:gravity="center"
android:text="\u2022"
android:textSize="#dimen/match_code_digit_size"
tools:ignore="HardcodedText" />
<TextView
android:id="#+id/code2"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:layout_marginBottom="20dp"
android:gravity="center"
android:text="\u2022"
android:textSize="#dimen/match_code_digit_size"
tools:ignore="HardcodedText" />
<TextView
android:id="#+id/code3"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:gravity="center"
android:text="\u2022"
android:textSize="#dimen/match_code_digit_size"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k1"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:text="1"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k2"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:text="2"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k3"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:text="3"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k4"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:text="4"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k5"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:text="5"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k6"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:text="6"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k7"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:text="7"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k8"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:text="8"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k9"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:text="9"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
<Button
android:id="#+id/k0"
android:layout_width="#dimen/match_code_button_size"
android:layout_height="#dimen/match_code_button_size"
android:layout_column="1"
android:text="0"
android:textSize="#dimen/match_code_button_text"
tools:ignore="HardcodedText" />
</GridLayout>
<TextView
android:id="#+id/error"
style="#style/ErrorText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="#string/match_error"
android:visibility="invisible" />
</LinearLayout>
<FrameLayout
android:id="#+id/progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#80ffffff"
android:visibility="visible">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
</FrameLayout>
Sorry for large volume of layout, put it here 'as is'.
Pay attention to the bottom FrameLayout with id progress. Despite it has android:layout_height="match_parent", on the device it looks like "wrap_content" - has height only matching inner ProgressBar.
Though in Android Studio designer shown perfectly, occupying whole the view.
What's wrong?
Here is how layout looks in AS designer
and on the device (tried both emulator and real device, the same effect)
Try to change the root FrameLayout to RelativeLayout
You have two FrameLayouts. #id progress one and a LinearLayout one.
First a quick look at the developer.android.com
FrameLayout is designed to block out an area on the screen to display
a single item. Generally, FrameLayout should be used to hold a single
child view, because it can be difficult to organize child views in a
way that's scalable to different screen sizes without the children
overlapping each other.
So for your parent FrameLayout How many children you have?(2)
You can, however, add multiple children to a FrameLayout and control
their position within the FrameLayout by assigning gravity to each
child, using the android:layout_gravity attribute.
Is there any gravity in your both children? No not for the #id progress
Child views are drawn in a stack, with the most recently added child
on top. The size of the FrameLayout is the size of its largest child
(plus padding), visible or not (if the FrameLayout's parent permits).
So first you add linear layout and then you add FrameLayout so.. child FrameLayout should be on top and it is. That's your issue right?
Even your layout is long in can be shorten to this
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:layout_gravity="center"
android:background="#121"
android:orientation="vertical">
</LinearLayout>
<FrameLayout
android:id="#+id/progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#567"
android:visibility="visible">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
</FrameLayout>
</FrameLayout>
Output (i added an image for linear layout you are missing gravity in your child frame layout):
I had the same problem and managed to fix it. Seems like nobody noticed that but the source of your problem is a GridLayout. As you can see in the blueprint there is no problem with FrameLayout as it is indeed matching the parent. The items of your GridLayout have a fixed size and that is wrong. You need to set the weights for every item in the GridLayout so that the items can stretch to fit any screen resolution. But weights in GridLayout need API 21. So i suggest you use nested LinearLayout's with item's weights set to 1.
The issue I had on my project is, I had two Frame layouts with the same Id.
The solution is to assign unique ids to frame layouts.
Hope this helps future readers.

Achieve Layout Elegantly Without Many Nested Layouts

I am attempting to create this layout in AXML:
However I am unsure of the easiest way to create this and avoid many nested Layout's. I am thinking to have an outer LinearLayout (horiz) with 2 RelativeLayouts for each column (then add the widgets in there).
So like this:
But with this current layout its not positioning correctly:
Can you suggest the easiest way to achieve this layout (ie, not involving many nested layouts) and why my code below isn't displaying correctly?
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:minWidth="25px"
android:minHeight="25px"
android:background="#161615">
<!-- Listing Details Section -->
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="0.5">
<Mvx.MvxImageView
android:id="#+id/listingIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
local:MvxBind="ImageUrl LlistingIcon"
android:layout_alignParentLeft="true" />
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15dp"
android:text="First name Last name"
android:layout_toRightOf="#+id/listingIcon" />
<TextView
android:id="#+id/datePosted"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15dp"
android:text="2 days ago"
android:layout_toRightOf="#+id/listingIcon" />
</RelativeLayout>
<RelativeLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="0.5">
<TextView
android:id="#+id/likes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15dp"
android:text="13 likes"
android:layout_alignParentLeft="true" />
<TextView
android:id="#+id/comments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15dp"
android:text="4 comments"
android:layout_alignParentLeft="true" />
<Mvx.MvxImageView
android:id="#+id/moreInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
local:MvxBind="ImageUrl MoreInfoIcon"
android:layout_alignParentRight="true" />
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
You should be able to accomplish this with the below layout (using a single RelativeLayout). You may need to adjust padding/margin to your needs to get exactly what you want. I haven't tested it but this should get you close.
<RelativeLayout
...>
<Mvx.MvxImageView
android:id="#+id/listingIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="use appropriate margin for your needs/>
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15dp"
android:text="First name Last name"
android:layout_toRightOf="#+id/listingIcon" />
<TextView
android:id="#+id/datePosted"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15dp"
android:text="2 days ago"
android:layout_below="#+id/name" /> <!-- see this change -->
<Mvx.MvxImageView
android:id="#+id/moreInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
local:MvxBind="ImageUrl MoreInfoIcon"
android:layout_alignParentRight="true" />
<TextView
android:id="#+id/likes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:textSize="15dp"
android:text="13 likes"
android:layout_alignPToLeftOf="#id/moreInfo" /> <!-- changed -->
<TextView
android:id="#+id/comments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:textSize="15dp"
android:text="4 comments"
android:layout_toLeftOf="#id/moreInfo"
android:layout_below="#id/likes" />
</RelativeLayout>
You can actually achieve this with a single horizontal LinearLayout and three children.
Your first child would be a TextView with a compound drawable.
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableLeft="#drawable/some_icon"
/>
The text can be either hardcoded or something you set dynamically, but you can use the power of Android's spans if you need different sections of the text to be styled differently. This way you avoid creating unnecessary TextViews.
Your second child would be another TextView, again with spans if you need to style content differently, and your third child an ImageButton.
This approach will require at most two layout passes to succeed. (One if you don't use weights. It may even still be one pass if you specify weight for only one child and give it a width of 0dp, but I can't quite remember).
A single relative layout could also give you what you want, but requires the definition of confusing constraints and requires two measure/layout passes.

ActionBar Tab with custom View not centered

I need to use a custom View for my tabs, the problem is that fill_parent doesn't work (as seen here).
So I need to use margin and stuff, but in order to have the view centered inside the tab in all configuration (landscape/portrait, or on a tablet where the height of the tabs will change) it's a bit tricky to do.
I don't know what value to use on each configuration. Plus, I don't find the default layout that the system uses to start with.
I'd recommend that you use the ActionBar Tab styles. This is clean and simple. For example (zeroing in on the TabView):
<style name="MyActionBar" parent="#style/android:Widget.Holo.ActionBar">
<item name="android:titleTextStyle">#style/MyActionBarTitleText</item>
<item name="android:attr/actionBarTabTextStyle">#style/MyActionBarTabText</item>
<item name="android:attr/actionBarTabStyle">#style/MyActionBarTabStyle</item>
</style>
<!-- styling for the tabs -->
<style name="MyActionBarTabStyle" parent="#style/android:Widget.Holo.Light.ActionBar.TabView">
<item name="android:background">#drawable/tab_bar_bg_master</item>
<item name="android:gravity">center</item>
</style>
(I'll also note that the tabs are highly styleable by using custom Drawables. But that's a topic for another day!)
the above reply from #Stephane-Mathis is on the right track, but I couldn't get it to work just right in my code. Here's a simpler version that uses the same concept.
Again, the idea is to force your view to be much taller than the tab itself.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="3dp"
android:paddingBottom="3dp">
<View
android:id="#+id/spacer_1"
android:layout_width="0dp"
android:layout_height="1000dp"
android:layout_weight="1" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="#drawable/ic_tabicon_1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="6dp"
android:layout_gravity="center_vertical"
android:textColor="?accentColor"
android:text="My Albums" />
<View
android:id="#+id/spacer_2"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
The spacer_1 and spacer_2 views exist to pad the ImageView and TextView evenly on the left and right side. Furthermore, the height on spacer_1 is set to something absurdly high (1000dp) so force the parent view to be excessively tall. Then the ImageView and the TextView re both set to center_vertical.
So, if you want to do that you will need to do a bit of dirty stuff.
Since fill_parent doesn't work, you need to force the root view to have more height than the tab height and then center what you really need. So my first LinearLayout is useless, and the second one will be in the center of the tab.
Here is what I used. I just wanted one textview with another one at the top right of it.
<?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">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="invisible">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<TextView
android:id="#+id/tv_tab_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/tv_tab_title"
android:layout_gravity="right"
android:background="#drawable/bg_notification"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:text="1"
android:gravity="center"
android:minWidth="14dp"
android:textStyle="bold"
android:textColor="#color/blanc"
android:textSize="8dp" />
<TextView
android:id="#+id/tv_tab_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textColor="#color/noire"
android:textSize="12dp"
android:textStyle="bold" />
<TextView //this has the same height as the `tv_tab_count` so it remains centered vertically
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/tv_tab_title"
android:layout_gravity="right"
android:background="#0f0"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:text="1"
android:textSize="8dp"
android:visibility="invisible" />
</LinearLayout>
This work for the vertical alignment but the view only has the width of the content I put in my textview. So if you need to use the complete width, you should put a really really long word in one of the invisible textviews.

Centering CheckBox Views

If you're interested in RadioButtons in addition to (or instead of) CheckBoxes, see this question instead.
Despite the presence of
<item name="android:layout_gravity">center_horizontal</item>
in the style file, the two checkboxes are not centered, but appear "left-justified".
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/MyLL"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="#+id/cb1"
style="#style/CB_style" />
<CheckBox
android:id="#+id/cb2"
style="#style/CB_style" />
</LinearLayout>
res/values/styles.xml
<style name="CB_style" parent="#android:style/TextAppearance.Medium">
<item name="android:layout_gravity">center_horizontal</item>
<item name="android:layout_weight">1</item>
<item name="android:gravity">center</item>
<item name="android:checked">false</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
You have android:layout_weight = 1. So your checkboxes fill all width of screen.
Remove android:layout_weight from style and add margin between checkboxes.
Gravity in Checkbox don't affect the inner tick button, only text.
EDIT
Ok, try this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/MyLL"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="0dp"
android:layout_height="5dp"
android:layout_weight="1"/>
<CheckBox
android:id="#+id/cb1"
style="#style/CB_style" />
<TextView
android:layout_width="0dp"
android:layout_height="5dp"
android:layout_weight="1"/>
<CheckBox
android:id="#+id/cb2"
style="#style/CB_style" />
<TextView
android:layout_width="0dp"
android:layout_height="5dp"
android:layout_weight="1"/>
</LinearLayout>
And remove layout_weight from style.
Another way is create custom checkbox. But I think it's too complicated for this problem.
Here's something that may help:
android:gravity vs android:layout_gravity
android:gravity is usually internal, usually asking the view itself what to do with the pixels it has
android:layout_gravity is usually external, usually asking the parent ViewGroup (LinearLayout/RelativeLayout/FrameLayout) how to position the view with extra pixels that the view is not using
If you are using a view with wrap_content, you probably want to use layout_gravity. If you are using a view with match_parent, you probably want to try gravity.
Sometimes wrapping another ViewGroup around a troublesome View can help with positioning. Views and ViewGroups go through an intricate "screen space" negotiating phase, and different Views (Buttons/TextView/ImageView/etc) and ViewGroups (LinearLayout/RelativeLayout/TableLayout/etc) have different rules and negotiating powers
This is why sometimes pairing a troublesome View with another parent like a FrameLayout or LinearLayout can make it behave all of the sudden
This is a little messy but it works, and yes it works as well for 3 or more checkbox inputs:
<LinearLayout
android:padding="0dip"
android:layout_width="0dp"
android:layout_weight="1"
android:hint="name"
android:layout_height="40dip"
android:textAlignment="center" android:layout_gravity="center"
android:orientation="horizontal"
>
<TextView
android:layout_width="0dip"
android:layout_height="1dip" android:layout_weight="1" android:text=" " />
<CheckBox
android:id="#+id/chk1"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:scaleX="1.5" android:scaleY="1.5"
>
</CheckBox>
<TextView
android:layout_width="0dip"
android:layout_height="1dip" android:layout_weight="1" android:text=" " />
<CheckBox
android:id="#+id/chk2"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:scaleX="1.5" android:scaleY="1.5"
>
</CheckBox>
<TextView
android:layout_width="0dip"
android:layout_height="1dip" android:layout_weight="1" android:text=" " />
</LinearLayout>
Try it in style
<item name="android:layout_width">0dp</item>
I hope it will work.. thanks..
<style name="TextlessCheckBox" parent="android:Widget.Material.CompoundButton.CheckBox">
<item name="android:button">#null</item>
<item name="android:foreground">?android:listChoiceIndicatorMultiple</item>
<item name="android:foregroundGravity">center</item>
</style>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/MyLL"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:background="#ff0000"
android:gravity="center" >
<CheckBox
android:id="#+id/cb1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:background="#00FF00"
android:gravity="center" >
<CheckBox
android:id="#+id/cb2"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
ok, last try for today ;) you should post a picture next time, HOW it should look... well, now you ll have your LinearLayout divided into two similar wide part (red & green), and in every block your checkbox is in the center...did i got it right this time?!
Just add this to your LinearLayout :
android:gravity="center_horizontal"
This line specifies that anything inside this layout will be in the center.
The Full layout code :
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<CheckBox
android:id="#+id/cb1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox ONE"
/>
<CheckBox
android:id="#+id/cb2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CheckBox TWO" />
</LinearLayout>
Here is the output i got :

Combine layout_weight and maxWidth for views

I'm trying to make my layouts more landscape friendly, and a common pattern I have is to add a LinearLayout with some buttons (e.g. OK | Cancel) and just set a value for layout_weight so that the space is evenly distributed. The problem is that when you use a phone or (especially) a tablet in landscape mode, you end up with humongous buttons that look ridiculous. I tried setting maxWidth on the buttons and on the linear layout but to no avail. What would be the easiest way to achieve this? Namely, setting a maximum horizontal size for the view so that it does not grow to the whole width. I tried a bunch of different things, but none worked.
Here's a sample layout:
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="6dp"
android:paddingBottom="6dp">
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:enabled="false"
android:textStyle="bold"
android:text="#string/button1" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="#string/button2" />
</LinearLayout>
Note: I know I can create a new layout file for landscape and do magic there. I want to keep the specialized layout files to a minimum, and I would hope this does not require them.
After messing around quite a bit with relative layouts, I stumbled upon this answer, which is what I ended up using.
I don't have Eclipse here to test it, but I would use a RelativeLayout instead, something like:
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<View
android:id="#+id/centerView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginLeft="5dp"
android:layout_marginRight="5dp"
/>
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toLeftOf="#id/centerView"
android:enabled="false"
android:textStyle="bold"
android:text="#string/button1"
/>
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="#id/centerView"
android:text="#string/button2"
/>
</RelativeLayout>
As I said, I can't test it right now, but you can work around this idea.
On a side note, unless your layout is very simple, I usually create separate layouts for landscape. It's a little more work, but you can optimize the views much better that way. Specially, if you plan to support larger screens.
<RelativeLayout
android:id="#+id/rlMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="12dp"
android:layout_marginRight="12dp">
<View
android:id="#+id/vCenter"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerHorizontal="true"
android:layout_marginRight="5dp"
android:layout_marginLeft="5dp"/>
<Button
android:id="#+id/btnOne"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_toLeftOf="#id/vCenter"
<!--Change this for different widths-->
android:minWidth="200dp"/>
<Button
android:id="#+id/btnTwo"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:layout_toRightOf="#id/vCenter"
<!--Change this for different widths-->
android:minWidth="200dp"/>
</RelativeLayout>

Categories

Resources