How to limit the height of a ListView within a GridLayout?
Asked Answered
O

4

5

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>
Oldie answered 8/10, 2014 at 17:46 Comment(7)
Just so I understand your question, you want your ListView to be a static height and individually scrollable? As in, when you scroll within the ListView, the rest of the GridView will not scroll.Bickerstaff
Yes, the ListView should take all the available space. It should also be scrollable, but the GridView should not scroll and the TextView below the ListView should always be visible.Oldie
You can't do what you want simply by using a GridLayout directly. Even the documentation states that the widget doesn't support the concept of weight and suggests wrapping the children in a LinearLayout.Forbidden
From here: "GridLayout does not provide support for the principle of weight. In general, it is not therefore possible to configure it 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..."Hardy
So, since the ListView's height isn't fixed and expands with a new content you cannot achieve the desired behavior via xml attributes unless you use a LinearLayout with weight or RelativeLayout as a wrapper for the ListView and TextView.Hardy
@Hardy The documentation talks about distributing excess space between multiple components. I do not have multiple components to take excess space, but only a single component - the ListView.Oldie
i wonder why u are using GridLayout although it contains only ListView and TextView. If u don't want to scroll to show TextView, just use RelativeLayout. Use correct layout class.Phraseology
H
7

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>
Hardy answered 16/10, 2014 at 20:36 Comment(0)
B
1

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.

Bickerstaff answered 14/10, 2014 at 13:53 Comment(0)
J
0

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.

Julietjulieta answered 14/10, 2014 at 13:47 Comment(4)
Where/how is ListView set to "wrap_content"?Oldie
well you are right that it is not defined with GridLayout children, but from your description it looks like it behaves as it was (I havent tried myself). But my suggestion is still valid. GridView will send you into onMeasure method size of available space. If you use this values with setMeasuredDimensions. You should be restricted on available space.Julietjulieta
It is like Onik said in his comment, but if you want to avoid wrapper layouts you can use my suggestion. Do you understand in principle or should I provide you with some code?Julietjulieta
I am looking for an XML solution or an explanation why this cannot be done with XML alone.Oldie
W
0

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>
Winner answered 21/10, 2014 at 11:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.