美文网首页Android技术安卓收藏
Android Listview设置Header或Footer隐

Android Listview设置Header或Footer隐

作者: 小木桨 | 来源:发表于2016-04-28 19:34 被阅读1915次

    在Android开发中,会经常遇到给ListView添加自定义的HeaderView或FooterView,如果我们想隐藏HeaderView或FooterView的时候,一般会调用view的setVisibility方法设置属性值GONE,这时候发现View元素虽然正常的被隐藏了,但是view所占的高度却没有被改变,view所占的位置还是被显示了出来,从而出现一片空白区域

    解决思路:

    解决问题之前首先需要明白为什么会出现这个问题?

    通过源码可以看到,在常用的ViewGroup,例如LinearLayout,在onMeasure方法中对每个childView执行measure前,都会判断childView的visibility是否为GONE,如果是GONE,则不对这个childView执行meaure操作,也就是这个childView的高度不会被计算到LinearLayout的高度中,下面是LinearLayout中onMeasure方法的代码片段:

     // See how tall everyone is. Also remember max width.
            for (int i = 0; i < count; ++i) {
                final View child = getVirtualChildAt(i);
    
                if (child == null) {
                    mTotalLength += measureNullChild(i);
                    continue;
                }
    
                if (child.getVisibility() == View.GONE) {
                   i += getChildrenSkipCount(child, i);
                   continue;
                }
                。。。
    

    但是view在measure自己的时候,并不会去判断自身的visibility是否为GONE,也就是只有在parentView中才会去判断,所以当对LinearLayout里面的一个子View设置Visibility为GONE时,这个View是不会被measure的,最终也是不会被显示的。
      了解了常用ViewGroup是如何测量宽高的,再来看一下ListView里面是如何测量的,通过阅读源码可以看到如果ListView的widthMode、heightMode任意一个是unspecified时,就会调用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在对ChildView执行meaure之前,并没有判断visibility为GONE的情况,当lpHeight > 0 时,说明在xml布局文件中给ListView设置过了一个尺寸值,所以不会出现问题,而在else里面,设置mode为UNSPECIFIED,目的就是为了让ChildView自己去测量大小,而ChildView在measure自己时是不会考虑visibility情况的,看到这里也就明白了为什么在设置HeaderView或FooterView的visibility为GONE时,会出现空白了!

    解决方法:

    弄明白了原因以后就知道该如何解决这个问题了,不能直接设置HeaderView或FooterView的visibility为GONE,而是需要在HeaderView或FooterView外层嵌套一层parentView,并且设置这个ParentView的layout_height="wrap_content",然后对里面的childView设置visibility为GONE或VISIBLE就会解决这个问题

    相关文章

      网友评论

      • bc65d707fcd0:赞赞赞
      • 我like砂糖:赞,解决了我的问题
      • Tyhoo_Wu:感谢楼主分享,最后的一段话把握现在做的项目的问题解决了,感谢
      • ac90cd96f51b:谢谢分享!
      • 1d24f2b2e34f:感谢楼主,headerview隐藏占位这个问题如果不从原码入手确实想不到根本原因

      本文标题:Android Listview设置Header或Footer隐

      本文链接:https://www.haomeiwen.com/subject/bojhrttx.html