由Recyleview添加headview 列表不显示想到的

大致需求场景:
类似于个人主页,上端展示一些个人信息,下边是其个人一些作品列表,因为要求滑动顺着 整页滑动。
Recyleview添加headview,结果却是 列表不显示。
思考了一下:
在Avtivity的onCreate()中直接调用View组件的getWidth()、getHeight()、getMeasuredWidth()、getMeasuredHeight()、getTop()、getLeft()等方法是无法获取到真实值的,只会得到0。

这是因为View组件布局要在onResume回调后完成。

然而 是在onCreate()中Recyleview执行的addheadview(),可能是这个原因引起的,高度为0所以不显示。

想到的解决办法:

1getViewTreeObserver().addOnGlobalLayoutListener()重新设置高度

使用getViewTreeObserver().addOnGlobalLayoutListener()来获得宽度或者高度。OnGlobalLayoutListener 是ViewTreeObserver的内部类,当一个视图树的布局发生改变时,可以被ViewTreeObserver监听到,这是一个注册监听视图树的观察者(observer),在视图树的全局事件改变时得到通知。ViewTreeObserver不能直接实例化,而是通过getViewTreeObserver()获得。

需要注意的是:OnGlobalLayoutListener可能会被多次触发,因此在得到了高度之后,要将OnGlobalLayoutListener注销掉。

mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(  
    new OnGlobalLayoutListener() {  
        @Override  
        public void onGlobalLayout() {  
                                                                                                                                                                                                                                    
            mHeaderViewHeight = mHeaderView.getHeight();  
            getViewTreeObserver()  
                    .removeGlobalOnLayoutListener(this);  
        }  
    });  

转念一想,重新请求一下不就好了

2.recyclerview.requestLayout();

请求数据解析完后,执行recyclerview.requestLayout();
requestLayout() 控件会重新执行 onMesure() onLayout() ,解决问题。

引发思考笔记

3invalidate和requestLayout的区别

简单地说invalidate() ,是自定义View 的时候,重新执行onDraw()方法。详情见图,比较直观

由Recyleview添加headview 列表不显示想到的_第1张图片
image.png

图片来源网络
View的measure方法‘

 public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
    ..........

    final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
    ..........

    if (forceLayout || needsLayout) {
    ..........

            onMeasure(widthMeasureSpec, heightMeasureSpec);
            mPrivateFlags |= PFLAG_LAYOUT_REQUIRED;
    }

}

requestLayout时对View设置了PFLAG_FORCE_LAYOUT标记位,而invalidate则没有,所以在调用invalidate重绘时forceLayout 为false,也就是最上层的控件就不会调用onMeasure方法,那么下面的控件也肯定不会进行重新测量。而重新测量的控件又会被标记上PFLAG_LAYOUT_REQUIRED。

layout方法

  public void layout(int l, int t, int r, int b) {
    ..........

    boolean changed = isLayoutModeOptical(mParent) ?
            setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);
    if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {
        onLayout(changed, l, t, r, b);
    }

     ..........
}

  调用onLayout方法,要么位置变化,changed为true,要PFLAG_LAYOUT_REQUIRED标记位,所以invalidate的重绘顶层控件也不会调用onLayout方法,invalidate不会经过measure和layout这两个过程。 

或者可以说是invalidate应该是在控件内容或是可见性发生了变化,而其大小位置等不会发生变化时调用,所以不需要重新测量布局,而requestLayout则是大小位置发生了变化则调用。

你可能感兴趣的:(由Recyleview添加headview 列表不显示想到的)