I have a GridLayout
containing a ListView
and a TextView
. When items are added
to the ListView
it will grow in size and push the TextView
below it out of the
screen. I thought that by setting layout_gravity="fill"
on the ListView it
would not grow at all but rather take up all the available space.
How do I configure the ListView
to take up the available space instead of
growing and pushing views below it out of the screen?
I am looking for a solution using a GridLayout
. I am aware that in my case a
LinearLayout
would work aswell. However this is just a minimal test case to
illustrate my problem.
I do not want to set the height programmatically, if possible.
<android.support.v7.widget.GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:columnCount="1"
app:useDefaultMargins="true" >
<ListView
app:layout_gravity="fill" />
<TextView
android:text="TextView" />
</android.support.v7.widget.GridLayout>
This answer extends my comments to the question and attempts to explain why this cannot be done with XML via GridLayout's attributes
.
Adding GridLayout
to the framework allowed solving a range of drawbacks regarding nested layouts, one of wich was "inability to control alignment along both horizontal and vertical axes simultaneously"
as described in the article New Layout Widgets: Space and GridLayout by Philip Milne.
This alignment control is performed by layout_gravity
parameter whose description
states that the parameter "specifies how a component should be placed
in its group of cells",
(NOT within a root layout
). Basically, it's the same as that of LinearLayout
, which also mentioned in the article: "Alignment/gravity also works just like gravity in LinearLayout..."
And as we know, for LinearLayouts
, once a view has taken the whole height of the screen (like ListView
in your case), the views below it go behind the screen if the layout oriention was set to "vertical"
.
If we look at the GridLayout.LayoutParams documentation we won't find any parameter which would allow a component within a cell group to stick to a certain position of the parent layout and stay at the position independent of the size of other components within the same group; similar to the layout_align[...]
parameters of a RelativeLayout.
My best guess about the absence of this kind of parameters in GridLayout
is better alignment control compare to nested layouts.
I'm sure you know a solution(s) for your problem using an approach other than GridLayout's
attributes. I'll just suggest one to make the answer look accomplished:
<GridLayout
... >
<RelativeLayout
... >
<TextView
...
android:id="@+id/tv"
android:layout_alignParentBottom="true" />
<ListView
...
android:layout_above="@id/tv">
</ListView>
</RelativeLayout>
</GridLayout>
You can programmatically set the height of the ListView as follows:
ListView listView = (ListView) findViewById(R.id.listview);
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) listView.getLayoutParams();
layoutParams.height = listHeight;
listView.setLayoutParams(layoutParams);
listView.setAdapter(listAdapter);
However, I can't think of a way to make this scale well for multiple devices.
Only way you can limit size of ListView with wrap content as height, is extending class, overriding onMeasure method and setting your limit for height there. I am not aware of any xml params whích would give you desired effect.
If you want, you can set your TextView inside a footer, and then the ListView will not push it. Altough I'm not sure if that is what you want
<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Footer aligned to bottom -->
<RelativeLayout
android:id="@+id/footer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/background"
android:gravity="center" >
<!-- TextView Here -->
</RelativeLayout>
<!-- Content below header and above footer -->
<RelativeLayout
android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="@id/footer"
android:gravity="center" >
<!-- ListView Here -->
</RelativeLayout>
</GridLayout>
You should use another layout as a parent for ListView
and TextView
and position them as you want.
<android.support.v7.widget.GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:columnCount="1"
app:useDefaultMargins="true" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_above="@+id/text_view_id" />
<TextView
android:id="@+id/text_view_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="TextView" />
</RelativeLayout>
</android.support.v7.widget.GridLayout>