Android How to reuse a header layout as an empty view in a ListView
Asked Answered
A

2

3

I've been grappling with this problem throughout the life of my project. I have many lists in my project and most of them have headers. I have been making a separate layout file and adding it to the list using addHeaderView(). The problem is that when the data (ArrayList, in my case) is empty, the header doesn't appear. After hours of searching for a way to reuse the header layout as an empty view, I gave up and decided to replicate the layout in code and assign it as an empty view using setEmptyView(). The problem with this is that a lot of the headers contain clickable views and so I have to double all of my clickable logic for every view that is duplicated. I tried to include the header before but failed, mostly because I still don't quite understand how layouts are inflated, etc.

Finally, I have come up with a solution that I would like to share with the community, in case others are having a similar problem. I don't know if this is the best way to solve this problem and any feedback or suggestions would definitely be welcomed.

here is the code for the layout that contains the list list view:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
>
    <ListView
        android:id="@+id/lv_my_list"
        style="@style/ListStyle"
        android:headerDividersEnabled="false"
    />
    <include
        layout="@layout/my_list_header"
        android:id="@+id/my_list_empty"
    />
</LinearLayout>

the style defines the layout width and height among other things.

now I have the layout file that contains the header view

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:id="@+id/my_list_header"
>
    <Button 
        android:id="@+id/my_list_button"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="Click Me"
    />
</LinearLayout>

I know LinearLayout is not very efficient and I am experimenting with using merge or other efficiency measures, but this is the first version that works so I'm going with it for now. Finally the code:

// set up the header
myListView = (ListView)findViewById(R.id.lv_my_list);
View header = View.inflate(this, R.layout.my_list_header, null);
Button b = (Button)header.findViewById(R.id.my_list_button);
b.setOnClickListener(this);
myListView.addHeaderView(header);

// set up the empty view        
LinearLayout ll = (LinearLayout)findViewById(R.id.my_list_empty);
b = (Button)ll.findViewById(R.id.my_list_button);
b.setOnClickListener(this);
meLocalListView.setEmptyView(ll);

The reason I wrapped the button in a layout is because I can set each instance of the button to use this as an OnClickListener and then refer to both of them with a single id: R.id.my_list_button in my onClick method. I need to test this a lot more but it seems to work for now. I haven't implemented it on all my lists yet, just the one so it might not work in all situations. If you have any suggestions please let me know because this has been a problem for me for a long time now. One problem might be that if you want to instantiate the button from the ID you would probably have to go through this entire process again to access the correct IDs?

Adherent answered 25/1, 2011 at 20:20 Comment(1)
Here is the solution -- > https://mcmap.net/q/37431/-addheaderview-does-not-work-when-the-list-is-emptyTraceable
I
1

If you want to show the header of a ListView when the list is empty, what you really want to do is to show the list itself rather than a separate empty view. So, the simplest way is to check whether your list is empty and set the list visible if it is not already:

getListView().setVisibility(View.VISIBLE);

You can test this very easily with the following code:

public class TestListActivity extends ListActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_listview);

        // create the empty grid item mapping
        String[] from = new String[] {};
        int[] to = new int[] {};

        // prepare the empty list
        List<HashMap<String, String>> fillMaps = new ArrayList<HashMap<String, String>>();

        // fill in the grid_item layout
        SimpleAdapter adapter = new SimpleAdapter(this, fillMaps, R.layout.test_listitem, from, to);

        View listHeader = 
                ((LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE))
                .inflate(R.layout.test_listheader, null, false);

        getListView().addHeaderView(listHeader);
        getListView().setAdapter(adapter);
    }
}

The list is empty, but the header is visible.

Incongruent answered 27/4, 2012 at 8:59 Comment(1)
Where do you set the listview visibility in your code sample?Slaby
F
0

My solution is to create a view with the layout for the header, but set the background to be the same as the list items. android:background="@android:drawable/list_selector_background"

But my solution does not work if I use 'include' to embed the header layout from another layout file. Do not know why.

Fichte answered 13/3, 2011 at 1:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.