How to configure ListView to automatically change its height?

前端 未结 5 1582
梦毁少年i
梦毁少年i 2021-01-03 04:50

I have three ListView widgets in the same LinearLayout. Something like this (I\'m omitting XML elements that are not relevant in this example):

相关标签:
5条回答
  • 2021-01-03 05:29

    try this... list view real height

    list view xml coding

    <ListView
     android:id="@+id/my_listview"
     android:layout_width="match_parent"
     android:layout_height="match_parent" />
    

    list view java coding

        ListView lView = (ListView)findViewById(R.id.my_listview);
        lView.setAdapter(adapter);
        setListViewHeightBasedOnChildren(lView);
    

    setListViewHeightBasedOnChildren method

    public static void setListViewHeightBasedOnChildren(ListView listView) {
        ListAdapter listAdapter = listView.getAdapter();
        if (listAdapter == null) {
            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);
        listView.requestLayout();
    }
    
    0 讨论(0)
  • 2021-01-03 05:36

    i found a solution on set ListView Height Based On Children, this work

    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);
        listView.requestLayout();
    }
    
    0 讨论(0)
  • 2021-01-03 05:38

    Instead of editing my previous answer, here's my actual version (after finally the case became the issue and I had to fix it)

        @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0));
    
        int childHeight = getMeasuredHeight() - (getListPaddingTop() + getListPaddingBottom() +  getVerticalFadingEdgeLength() * 2);
    
        // on a first run let's have a space for at least one child so it'll trigger remeasurement
        int fullHeight = getListPaddingTop() + getListPaddingBottom() + childHeight*(getCount());
    
        int newChildHeight = 0;
        for (int x = 0; x<getChildCount(); x++ ){
            View childAt = getChildAt(x);
    
            if (childAt != null) {
                int height = childAt.getHeight();
                newChildHeight += height;
            }
        }
    
        //on a second run with actual items - use proper size
        if (newChildHeight != 0)
            fullHeight = getListPaddingTop() + getListPaddingBottom() + newChildHeight;
    
        setMeasuredDimension(getMeasuredWidth(), fullHeight);
    }
    

    The trickiest part is that the onMeasure gets called twice, first for approx layout and then after items added for a precise one and both have to return sane results.

    0 讨论(0)
  • 2021-01-03 05:43

    I've implemented it this way (code is work in progress so it's more a idea source than solution):

    package com.customcontrols;
    public class NoScrollListView extends ListView
    {
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
        {
            super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0) );
    
            // here I assume that height's being calculated for one-child only, seen it in ListView's source which is actually a bad idea
            int childHeight = getMeasuredHeight() - (getListPaddingTop() + getListPaddingBottom() +  getVerticalFadingEdgeLength() * 2);
    
            int fullHeight = getListPaddingTop() + getListPaddingBottom() + childHeight*(getCount());
    
            setMeasuredDimension(getMeasuredWidth(), fullHeight);
        }
    }
    

    the calculation's not perfect, but it's close and works so far. after that you just create a layout like this:

    ScrollView com.customcontrol.NoScrollListView com.customcontrol.NoScrollListView com.customcontrol.NoScrollListView /ScrollView

    The scrollView's crucial since you can easily run out of screen bounds.

    PS. The calculation's rectum-driven since most of the calculation methods in ListView&Co are package private which is quite a strange choice for publicly inheritable classes for UI.

    0 讨论(0)
  • 2021-01-03 05:45

    You can try iterating over the ListView's rows (see methods on ViewGroup), find their heights, sum them, and change your ListView height.

    That being said, I fully expect this to be awful:

    • You need to take into account the screen size, so your lists do not go past the bounds of the screen
    • You need to take into account orientation changes
    • You need to take into account any modifications to your data (e.g., deleting rows may require your list to shrink)
    • Etc.

    If your goal really is to have a single list, but you have three sources of data, merge the data and put it into a single list. My MergeAdapter can help here.

    0 讨论(0)
提交回复
热议问题