Reputation: 37516
I'm struggling to get a layout looking correctly, and I've tried to produce the shortest, smallest possible example of my problem.
My goal is to have a header and footer View, at the top and bottom of the screen, with a ListView
in between the two, with another View (let's call it the label, it's the gray box from the screen shots) directly below the ListView
. This label, and the footer should always be shown when ListView
needs to scroll.
When the ListView
does not need to scroll (this is correct):
When the ListView
needs to scroll, the footer and the gray box are pushed off screen (wrong):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="header"
android:padding="20dp"
android:textSize="18sp"
android:background="@color/red"/>
<ListView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@android:id/list" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="this should be directly below the ListView, but not pushed off screen when the ListView needs to scroll"
android:padding="5dp"
android:background="@color/light_gray"
android:textColor="@color/black"/>
<!-- Used to push the footer to the bottom -->
<View android:layout_width="0dp" android:layout_height="0dp" android:layout_weight="1"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="footer"
android:padding="20dp"
android:textSize="18sp"
android:background="@color/blue"/>
</LinearLayout>
public class TestActivity extends ListActivity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
ArrayList<String> items = new ArrayList<String>();
items.add("one");
items.add("two");
items.add("three");
items.add("four");
items.add("five");
items.add("six");
items.add("seven");
items.add("eight");
items.add("nine");
items.add("ten");
setListAdapter(new ArrayAdapter<String>(this, R.layout.simple_list_item_1, items));
setContentView(com.myproject.android.R.layout.test);
}
}
I've tried a few different approaches, such as giving the ListView
layout_weight="1"
and removing the blank View
that I use to push the footer to the bottom. This is almost what I want, it keeps the footer and label visible when the ListView
scrolls, but when it only has 1 or 2 items, I need the gray box right below the ListView
. I've also attempted to use a RelativeLayout
, without success. I guess I'm completely misunderstanding things.
Here's my attempt with a RelativeLayout
which still isn't correct.
<?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">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="header"
android:padding="20dp"
android:textSize="18sp"
android:background="@color/red"
android:id="@+id/header"
/>
<ListView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@android:id/list"
android:layout_below="@id/header"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="this should be directly below the ListView, but not pushed off screen when the ListView needs to scroll"
android:padding="5dp"
android:background="@color/light_gray"
android:textColor="@color/black"
android:layout_below="@android:id/list"/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="footer"
android:padding="20dp"
android:textSize="18sp"
android:background="@color/blue"
android:layout_alignParentBottom="true"
android:id="@+id/footer"/>
</RelativeLayout>
Upvotes: 10
Views: 9878
Reputation: 21
A solution that worked for me was to add positive padding to the bottom of the list view and negative padding to the top of the "footer". This will work in a linear layout or a relative layout.
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="50dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-50dp"/>
Upvotes: 2
Reputation: 2814
Two years late to answer the question, but I will leave my solution so it may help someone with the same problem. I solve this problem using 2 nested LinearLayouts and using layout_weigth. Maybe not the best performatic layout, but it reaches the desired effect.
You need to arrange your layout this way:
Now you have a layout with the list and the grey view and the list won't push the other views out of screen if it gets too big; you only need to move the footer view to the bottom of the screen.
5a. If you are using RelativeLayout as your root layout, you can do as sgallego said and use android:layout_alignParentBottom.
5b. But if you are using LinearLayout you need to create a third layout with layout_weigth and put inside the layout of step 4 and a empty view also with layout_weigth to fill the empty space.
Here is a commented example.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- Header -->
<TextView
android:id="@+id/RecordStudy_StudyLabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/RecordStudy_StudyLabel"
android:textSize="@dimen/text_large" />
<!-- Body -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" >
<!--
This layout encapsules the list and the button that must be immediately
below the list with a wrap_content height, so the list plus the button
fills only as much space as they need (if the list is not big enouth to
fill the entire screen).
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<!--
Layout with varaible size with a list inside.
Using layout_weight tells android that this layout should not grow
greater then the screen, but uses only the free space.
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical" >
<!--
Inside this limited height layout, there is a list with height
wrap_content so it can grow as much as it needs INSIDE the
layout (through scrolling).
-->
<ListView
android:id="@+id/RecordStudy_StudyList"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<!-- Button immediately below the list -->
<Button
android:id="@+id/RecordStudy_AddStudy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/RecordStudy_AddStudy" />
</LinearLayout>
<!-- Space between the list and the footer -->
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
<!-- Footer -->
<Button
android:id="@+id/RecordStudy_ConfirmButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/RecordStudy_ConfirmButton" />
</LinearLayout>
Upvotes: 1
Reputation: 9101
One solution that I implemented and found useful was to keep the listview inside a linear layout with fixed height so that it doesn't extend and overlap other items.
Something like this:
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="header"
android:padding="20dp"
android:textSize="18sp"
android:background="@color/red"
android:id="@+id/header"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="150dip" //assume 150dip height is sufficient
<ListView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@android:id/list"
android:layout_below="@id/header"/>
</LinearLayout>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="this should be directly below the ListView, but not pushed off screen when the ListView needs to scroll"
android:padding="5dp"
android:background="@color/light_gray"
android:textColor="@color/black"
android:layout_below="@android:id/list"/>
Upvotes: 0
Reputation: 318
This layout adds the header a top of the screen and the footter and the bottom. The list fills the rest of the screen. With theses aproach list elements never be obscured by the footer. See how to add the gray box below the XML...
<?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">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="header"
android:padding="20dp"
android:textSize="18sp"
android:background="@color/red"
android:id="@+id/header"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="footer"
android:padding="20dp"
android:textSize="18sp"
android:background="@color/blue"
android:layout_alignParentBottom="true"
android:id="@+id/footer"/>
<ListView android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@android:id/list"
android:layout_below="@id/header"
android:layout_above="@id/footer"/>
</RelativeLayout>
Ok. This XML solves the problem of the missing footer. Now we have to add a gray box at the end of the list. I think there is two ways to do it:
Use the addFooterView method: http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)
Play with the adapter and the getViewTypeCount() method so you can define two types or elements: normal elements and footer element. http://developer.android.com/reference/android/widget/BaseAdapter.html#getViewTypeCount()
Upvotes: 7
Reputation: 30168
Add android:layout_weight="1"
to the listview. That will make it the biggest element in the LinearLayout, without pushing the other ones off the screen.
Upvotes: 10