2

I've done all of the research on the matter. I know that Google thinks it's pointless and that the developers, know that it's not. I also know that there is no known workaround, but I know that I am close to making one. The user DougW posted this code:

public class Utility {
    public static void setListViewHeightBasedOnChildren(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter(); 
        if (listAdapter == null) {
            // pre-condition
            return;
        }

        int totalHeight = 0;
        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            listItem.measure(0, 0);
            totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
    }
}

Which almost gets the job done for me. But when I try it, I get a NullPointer exception at the listItem.measure(0, 0) line. The listItem itself is initialized, but the method throws the exception anyway. Please tell me how I can fix this.

Here is my code:

public class ExpenseReportsActivity extends Activity {

    private ListView lvReports;
    private ExpenseReportListAdapter adapter;
    private Button btnSend;
    private Button btnCancel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.expensereports);

        lvReports = (ListView)findViewById(R.id.lv_reports);
        lvReports.setBackgroundResource(R.drawable.shape_expense_report_list);

        ColorDrawable cd = new ColorDrawable(0xFFffffff);
        lvReports.setDivider(cd);
        lvReports.setDividerHeight(1);

        adapter = new ExpenseReportListAdapter(this);
        lvReports.setAdapter(adapter);

        int totalHeight = 0;
        for (int i = 0; i < adapter.getCount(); i++) {
            View listItem = adapter.getView(i, null, lvReports);
            listItem.measure(0, 0);
            totalHeight += listItem.getMeasuredHeight();
        }

        ViewGroup.LayoutParams params = lvReports.getLayoutParams();
        params.height = totalHeight + (lvReports.getDividerHeight() * (adapter.getCount() - 1));
        lvReports.setLayoutParams(params);
    }
}

Another workaround I am working on is using my custom view's onWindowFocusChanged method. It tells the exacts height of the view. The problem is that the event isn't fired while I am still in my Activiy's onCreate method, nor in my Activity's onWindowFocusChanged method. I tried a custom event, but it never fired (it was placed inside my custom view's onWindowFocusChanged method and the listener was in my Activity's onWindowFocusChanged method).

Kara
  • 6,115
  • 16
  • 50
  • 57
Boris Rusev
  • 642
  • 1
  • 10
  • 17
  • Boris, could you tell what are you actually trying to achieve? I'm asking because it looks like you are on a wrong way on a higher level. – Vit Khudenko Nov 04 '10 at 20:19
  • My client wants an expense report form which he fills and sends when ready. But in most cases the form will contain a lot of fields, which won't fit on the display height-wise. So I have been instructed to create the form, which consists of the list of fields plus a few buttons, and make it scroll (the entire form, not just the list). – Boris Rusev Nov 05 '10 at 09:02
  • Does the suggested `ListView.addFooterView(View v)` solve your problem? – Vit Khudenko Nov 08 '10 at 08:03
  • No sir. Maybe I am not implementing it right, but I don't understand why this should solve my problem? It's the same list, and I just add another item to it, only this time I don't assign any height. – Boris Rusev Nov 09 '10 at 11:16
  • Then most likely I still don't get your needs... And maybe other guys are unable to give any help just because they don't get what are you trying to achieve. Probably you should focus on explaining your needs in a more clear way. – Vit Khudenko Nov 09 '10 at 15:12
  • I agree. But without any intent to offend you people, I don't know how much more simpler can my purpose be. 1) I have a large list of two dozen lines. 2) Below and above that list I have a few layouts 3) The screen is not high enough. 4) So I want everything to be in one giant parent and I want to scroll that parent. – Boris Rusev Nov 09 '10 at 15:16
  • Ok, then it seems I got your needs correct from the first time. ListView has two methods for adding header and footer views: `ListView.addHeaderView(View v)` and `ListView.addFooterView(View v)`. They (footer and header) do scroll with the list. Note that LinearLayout is also a View, in other words you can put anything you want to footer and header and it'll sroll with the list. So I don't see any reason why the suggeted way don't solve your problem. – Vit Khudenko Nov 09 '10 at 19:51
  • No I understand your solution...It's a little embarrassing actually. I've been trying to design my activity with a ScrollView the whole time, while you were actually explaining to me why I don't really need it. I understand now :). Thank you sir, I will give it a try asap! – Boris Rusev Nov 10 '10 at 08:42
  • Yes, you don't need `ScrollView`! :) Sorry, I should have said it explicitly. – Vit Khudenko Nov 10 '10 at 09:04
  • Actually now I see the problem...I feel so awkward for bothering you every day with this, but yesterday I tried your solution. I have added the header and footer views. But the problem is that my list must have padding on the left and right side, and on top of it I must place a logo which has to fill the parent along its width. I will try Mike's solution, but if you can think of anything please let me know. Thank you. – Boris Rusev Nov 11 '10 at 07:14
  • Could you provide a scetch/rough of the desired layout? Because it is hard to understand exactly what you'd like to achieve. – Vit Khudenko Nov 11 '10 at 17:34

2 Answers2

9

Ok, as far as I got your needs I think you may just use the ListView.addFooterView(View v) method:

http://developer.android.com/reference/android/widget/ListView.html#addFooterView(android.view.View)

It will allow you to have all your list items + "a few buttons" footer to be scrolled as a single block.

So the code should be smth like that:

import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;

public class YourActivity extends ListActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        LayoutInflater factory = getLayoutInflater();
        LinearLayout footer = 
            (LinearLayout) factory.inflate(R.layout.your_a_few_buttons_footer, null);

        getListView().addFooterView(footer);

        String[] array = new String[50];
        for (int i = 0; i < 50;) { array[i] = "LoremIpsum " + (++i); }

        setListAdapter(
            new ArrayAdapter<String>(this, R.layout.list_item, array)
        );
    }   
}

Note, the doc says addFooterView() should be called BEFORE the setListAdapter().

UPDATE: to add a View at the top of the list use ListView.addHeaderView(View v). Note that, for instance, LinearLayout is also a View. So you can put anything you want as a header or a footer and it'll be scrolled with the list as an indivisible block.

Vit Khudenko
  • 28,288
  • 10
  • 63
  • 91
  • Hello Arhimed, it appears as though the solution Boris found is what I am looking for. I am very new to this and for the first time today, I used ListActivity to list some items using my own layout. My layout had scrollview in it and I had assumed that it'd all work perfectly fine. Of course, I was completely wrong and the issue appears to be very complicated for a newbie like me. Did you have to change anything in the layout file to make sure it scrolls? – railslearner Mar 17 '12 at 09:29
  • @railslearner: Sorry, man, it is unclear what issue you have. I recommend to create a separate question where you describe in details (showing you layout xml, list item xml, etc) your problem. The Android community is rather big so you'll quickly get a good answer. Feel free to post a link on your question here as the next comment - I'll try to check it too. – Vit Khudenko Mar 17 '12 at 10:22
  • http://stackoverflow.com/questions/9749430/android-listactivity-scrollview-how-to-get-a-list-to-scroll – railslearner Mar 17 '12 at 11:00
  • Thanks for your reply Arhimed. Here's a link to the question – railslearner Mar 17 '12 at 11:01
  • @railslearner: I was out of network covarage for a week. It's cool to see your problem has been solved very quickly once you've spent time to stating it clearly. – Vit Khudenko Mar 25 '12 at 10:59
  • @Arhimed **This can be an alternate solution of this problem.Please check post of** "Atul Bhardwaj" in this [link](http://stackoverflow.com/questions/6210895/listview-inside-scrollview-is-not-scrolling-on-android) – Atul Bhardwaj Jul 19 '12 at 06:18
1

Out of curiosity, is your layout using RelativeLayout? If so, calling measure(0,0) will always throw an NPE, but a LinearLayout will not. http://groups.google.com/group/android-developers/browse_thread/thread/5a947482d7dcb605

Change it to Linear and you can make that call. I hope that helps!


I have a situation in my app where I have paragraphs of text, imageviews, all sorts of information on a given subject...and then, depending on the item, there is possibly a ListView of comparison data in the middle of all of that info. About one in every 10 items has it, nestled between all the text. The comparison data is never more than 4 items at max, so I don't want the ListView to scroll, ever. I just want the ListView to appear in its entirety at the exact point I specify.

Adding them all as nested Linear Layouts is insane, so is using MergeAdapter to put all of that together when I may not even have a ListView on screen. And using complex ListView headers & footers is out of the question as well.

I'm not the first person to want that kind of functionality, and I won't be the last. The above solution is nearly perfect, it sizes my ListView so that it's full on screen, and all the scrolling comes from the ScrollView parent. (It's easy as sin to do on the iOS SDK, btw., and a lot of apps over there do similar things; we'll need a good solution for this.)

Mike P.
  • 1,920
  • 1
  • 18
  • 20
  • 1
    This doesn't work, because in 2.2 measure takes two integers as parameters. – Boris Rusev Nov 09 '10 at 11:13
  • 1
    @Boris, what doesn't work? I have this running flawlessly in 2.2. If anything, it's 1.6 that acts weirdly compared to 2.x. OH, I see what you mean. I meant that I DO NOT call `measure(0,0)` at all. I did not mean just call `measure()` without parameters, sorry. – Mike P. Nov 10 '10 at 16:41
  • 1
    Sorry I've misunderstood you as well sir. I will try it, thank you. – Boris Rusev Nov 11 '10 at 07:09
  • 1
    See my edit to my first answer. I suspect you're using RelativeLayout. – Mike P. Nov 12 '10 at 16:15