Home  >  Q&A  >  body text

adapter - Android布局——listview会根据数据数量自动调节高度吗

最近在看一个项目的源码,有一个实现listview里嵌套listview的功能,实现方式是用Adapter嵌套Adapter。但是在主Adapter里,有一个函数用于更改子listview的布局高度。

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.getpiderHeight() * (listAdapter.getCount() - 1));
        listView.setLayoutParams(params);
    }

显然这个函数会根据adapter中数据的个数调节listview布局的高度,那么为什么listview不会自己调节呢?

阿神阿神2720 days ago325

reply all(2)I'll reply

  • 大家讲道理

    大家讲道理2017-04-17 13:32:38

    Because nested ListView does not need and should not be able to scroll

    So in the code, you need to adjust the nested ListView to the height that can just display all the Children

    As for the ListView itself, it does not care about its own height and whether it can display all the Children, because in terms of the original design, it is a scrollable component.


    You can also read the code below to see the logic of ListView’s measure height
    Take a look at how the height of ListView is obtained in MeasureSpec.UNSPECIFIED mode

     @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // Sets up mListPadding
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    
            int childWidth = 0;
            int childHeight = 0;
            int childState = 0;
    
            mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
            if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||
                    heightMode == MeasureSpec.UNSPECIFIED)) {
                final View child = obtainView(0, mIsScrap);
    
                measureScrapChild(child, 0, widthMeasureSpec);
    
                childWidth = child.getMeasuredWidth();
                childHeight = child.getMeasuredHeight();
                childState = combineMeasuredStates(childState, child.getMeasuredState());
    
                if (recycleOnMeasure() && mRecycler.shouldRecycleViewType(
                        ((LayoutParams) child.getLayoutParams()).viewType)) {
                    mRecycler.addScrapView(child, 0);
                }
            }
    
            if (widthMode == MeasureSpec.UNSPECIFIED) {
                widthSize = mListPadding.left + mListPadding.right + childWidth +
                        getVerticalScrollbarWidth();
            } else {
                widthSize |= (childState&MEASURED_STATE_MASK);
            }
    
            if (heightMode == MeasureSpec.UNSPECIFIED) {
                heightSize = mListPadding.top + mListPadding.bottom + childHeight +
                        getVerticalFadingEdgeLength() * 2;
            }
    
            if (heightMode == MeasureSpec.AT_MOST) {
                // TODO: after first layout we should maybe start at the first visible position, not 0
                heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
            }
    
            setMeasuredDimension(widthSize , heightSize);
            mWidthMeasureSpec = widthMeasureSpec;        
        }
    

    reply
    0
  • 迷茫

    迷茫2017-04-17 13:32:38

    Because ListView needs to reuse ConvertView

    reply
    0
  • Cancelreply