views:

239

answers:

3

I've searched around for solutions to this problem, and the only answer I can find seems to be "don't put a ListView into a ScrollView". I have yet to see any real explanation for why though. The only reason I can seem to find is that Google doesn't think you should want to do that. Well I do, so I did.

So the question is, how can you place a ListView into a ScrollView without it collapsing to its minimum height?

A: 

You should not put a ListView in a ScrollView because a ListView already is a ScrollView. So that would be like putting a ScrollView in a ScrollView.

What are you trying to accomplish?

Mayra
I'm trying to accomplish having a ListView inside a ScrollView. I do not want my ListView to be scrollable, but there is no simple property to set myListView.scrollEnabled = false;
DougW
As Romain Guy said, this is very much not the purpose of a ListView. A ListView is a view that is optimized for displaying a long list of items, with lots of complicated logic to do lazy loading of views, reuse views, etc. None of this makes sense if you are telling the ListView not to scroll. If you just want a bunch of items in a vertical column, use a LinearLayout.
Mayra
The problem is that there are a number of solutions that a ListView provides, including the one you mention. Much of the functionality that Adapters simplify though is about data management and control, not UI optimization. IMO there should have been a simple ListView, and a more complex one that does all the list item reuse and stuff.
DougW
+1  A: 

Here's my solution. I'm fairly new to the Android platform, and I'm sure this is a bit hackish, especially in the part about calling .measure directly, and setting the LayoutParams .height property directly, but it works.

All you have to do is call Utility.setListViewHeightBasedOnChildren(yourListView) and it will be resized to exactly accommodate the height of it's items.

    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);
        }
    }
DougW
You've just recreated a very expensive LinearLayout :)
Romain Guy
Except a `LinearLayout` doesn't have all the inherent niceties of a `ListView` -- it doesn't have dividers, header/footer views, a list selector which matches the phone's UI theme colors, etc. Honestly, there's no reason why you can't scroll the inner container until it's reached the end and then have it stop intercepting touch events so that the outer container scrolls. Every desktop browser does this when you're using your scroll wheel. Android itself can handle nested scrolling if you're navigating via the trackball, so why not via touch?
Neil Traft
+2  A: 

Using a ListView to make it not scroll is extremely expensive and goes against the whole purpose of ListView. You should NOT do this. Just use a LinearLayout instead.

Romain Guy
Not arguing with your point, but can you cite a source that talks about how expensive it is and why? Re-engineering a list of items in a LinearLayout seems much more expensive with regard to dev time. I'd like to know why it's so expensive, and make that trade off decision myself.
DougW
The source would be me since I've been in charge of ListView for the past 2 or 3 years :) ListView does a lot of extra work to optimize the use of adapters. Trying to work around it will still cause ListView to do a lot of work a LinearLayout wouldn't have to do. I won't go into the details because there's not enough room here to explain ListView's implementation. This also won't solve the way ListView behaves with respect to touch events. There's also no guarantee that if your hack works today it will still work in a future release. Using a LinearLayout would not be much work really.
Romain Guy
Well that's a reasonable response. If I could share some feedback, I have much more significant iPhone experience, and I can tell you that Apple's documentation is far better written with regard to performance characteristics and use cases (or anti-patterns) like this. Overall, the Android documentation is far more distributed and less focused. I understand there are some reasons behind that, but that's a long discussion, so if you feel compelled to chat about it let me know.
DougW