• Android ListView的header footer设置visibility gone不起作用


      常用的ViewGroup,例如LinearLayout,在onMeasure方法内对每个child view执行measure前,会判断child view的visibility是否为gone。如果是gone,则不对这个child view执行measure操作,即这个child view的高度不被计算在linearLayout的高度里面。LinearLayout的measureVertical代码片段:

    if (child.getVisibility() == View.GONE) {
        i += getChildrenSkipCount(child, i);
        continue;
    }

      

      view在measure自己时,并不会去判断自己的Visibility是GONE。这个逻辑操作如上述代码所示,是在parent view里面做的。所以当对LinearLayout里面的一个childView设置Visiblility为gone时,这个view不会被measure,最终也不会被显示出来。

      在使用ListView时,经常会添加一些headerView、footerView。但是当设置headerView、footerView的visibility为gone时,却发现headerView、footerView虽然没有显示出来,但垂直方向其所占的位置还是被显示出来了,从而出现了空白区域。网上查到的解决办法是:不能直接设置headerView、footerView的Visibility为gone。而是要在HeaderView、FooterView外面包一层parent view(FrameLayout RelativeLayout 都可以),并设置layout_height=“wrap_content”。然后对里面的childView设置visibility为GONE、VISIBLE都会生效。查看源码,情况确实如此。

      ListView的onMeasure里面,如果ListView的widthMode、heightMode有一个是unspecified时(应该对应于在XML中没有对listView设置layout_width、layout_height),会调用方法measureScrapChild。如果没有unspecified的情况,则会调用measureHeightOfChildren方法,而此方法内部也会调用measureScrapChild方法。查看measureScrapChild方法:

    private void measureScrapChild(View child, int position, int widthMeasureSpec) {
        LayoutParams p = (LayoutParams) child.getLayoutParams();
        if (p == null) {
            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
            child.setLayoutParams(p);
        }
        p.viewType = mAdapter.getItemViewType(position);
        p.forceAdd = true;
    
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
                mListPadding.left + mListPadding.right, p.width);
        int lpHeight = p.height;
        int childHeightSpec;
        if (lpHeight > 0) {
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
        } else {
            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
        child.measure(childWidthSpec, childHeightSpec);
    }

      可以看出,listview在对child view执行measure前,没有判断visibility为gone的情况

      再看看里面的详细逻辑:

    • lpHeight>0时,说明在xml或者程序里面设置了一个确定的尺寸,这里没有问题;
    • else里面,设置mode为UNSPECIFIED,就是让child view自己去决定大小,child view在measure自己时,不会考虑VISIBILITY属性。

      else包含的逻辑:

    • lpHeight == 0:对应于在xml或者代码中设置尺寸为0,说明也是不起作用的,最终还是会显示出空白
    • lpHeight == -1:MATCH_PARENT
    • lpHeight == -2:WRAP_CONTENT

      三种情况,都会根据view实际的内容返回一个wrap_content的尺寸。这里就解释了为何设置headerView、footerView的visibility为gone时,会出现空白区域。

      如果外面包一层parent view(例如LinearLayout),并设置layout_height为wrap_content(按上面的分析,设置match_parent也是可以的),listView会调用调用额外的这个parent view的measure方法。而LinearLayout在measure时,会判断child view的visibility,如果为gone,则会返回0.最终这个额外的parent view返回给list view的尺寸就是0,从而解决了空白区域的问题。

      这个问题算是listview的一个feature吧!

  • 相关阅读:
    规则引擎.Net Core
    GDPR(Cookie处理)
    NSSM把.Net Core部署至 Windows 服务
    Consul实现服务治理1
    微服务
    Consul实现服务治理
    NET Core Web发布包
    NET API 分析器
    NET Core 2.1 Global Tools
    css3中-moz、-ms、-webkit,-o分别代表的意思,以及微信浏览器内核分析
  • 原文地址:https://www.cnblogs.com/zc9527/p/4591433.html
Copyright © 2020-2023  润新知