ViewGroup的LayoutParams理解[通俗易懂]

ViewGroup的LayoutParams理解[通俗易懂]LayoutParams是ViewGroup的一个内部类,声明方式如下publicstaticclassLayoutParams{publicstaticfinalintMATCH_PARENT=-1;publicstaticfinalintWRAP_CONTENT=-2;publicintwidth;publicintheight;

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

LayoutParams是ViewGroup的一个内部类,声明方式如下

public static class LayoutParams { 
   
        public static final int MATCH_PARENT = -1;
        public static final int WRAP_CONTENT = -2;
        public int width;
        public int height;
        
        public LayoutParams(Context c, AttributeSet attrs) { 
   
            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
            setBaseAttributes(a,R.styleable.ViewGroup_Layout_layout_width, R.styleable.ViewGroup_Layout_layout_height);
            a.recycle();
        }

        public LayoutParams(int width, int height) { 
   
            this.width = width;
            this.height = height;
        }
        
        public LayoutParams(LayoutParams source) { 
   
            this.width = source.width;
            this.height = source.height;
        }

 }

可以分析到,系统默认为ViewGroup自定义了宽高属性width和height,将其获取方式封装在LayoutParams中,系统考虑所有的View肯定都有宽高,所以就直接统一定义了,有一个疑问为啥不定义在View中,因为子View定义的宽高都是layout_width,layout_height,都是相对于父容器的
接下来分析,系统是如何将这个统一的ViewGroup.LayoutParams宽高属性给到View的呢?

阅读源码布局中View的加载流程,主要分析LayoutInflater#inflate这一步

public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { 
   
       
            final View temp = createViewFromTag(root, name, inflaterContext, attrs);

            ViewGroup.LayoutParams params = null;

            if (root != null) { 
   
                params = root.generateLayoutParams(attrs);
                if (!attachToRoot) { 
   
                    temp.setLayoutParams(params);
                 }
            }                    
}

分析关键代码,是root(ViewGroup)调用了generateLayoutParams(AttributeSet attrs);解析attrs中的layout_width和layout_height属性,将其值封装到了LayoutParams中,之后调用子View的setLayoutParams方法设置到子View中,之后子View就可以获取到width和height了

所以默认情况下父容器的generateLayoutParams只是解析layout_width和layout_height。如果子view需要支持margin属性,不重写父容器的generateLayoutParams的话,之后是子View是获取不到margin属性的

再分析下ViewGroup#generateDefaultLayoutParams,在上面我们分析了ViewGroup#generateLayoutParams它是作用在xml布局解析阶段为子View设置LayoutParams,那么ViewGroup#generateDefaultLayoutParams则是在代码中ViewGroup#addView中调用,我们看下源码

public void addView(View child, int index) { 
   
        if (child == null) { 
   
            throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
        }
        LayoutParams params = child.getLayoutParams();
        if (params == null) { 
   
            params = generateDefaultLayoutParams();
            if (params == null) { 
   
                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
            }
        }
        addView(child, index, params);
}

分析源码得知,generateDefaultLayoutParams的调用确实在动态addView中,同样的它也是默认创建的ViewGroup.LayoutParams,只支持width和height的

再分析下ViewGroup#generateLayoutParams(LayoutParams p),分析ViewGroup#addViewInner源码

private void addViewInner(View child, int index, LayoutParams params,boolean preventRequestLayout) { 
   
        if (!checkLayoutParams(params)) { 
   
            params = generateLayoutParams(params);
        }
}

分析可以知道,在addViewInner中会对params进行校验,如果不合法则调用generateLayoutParams(params)帮我们生成一个合法的LayoutParams.我们看下校验规则

protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 
   
        return  p != null;
}

ViewGroup默认的校验规则仅仅是不为空,相关宽松,LinearLayout等一般都会重写,有兴趣可以看源码

再分析下ViewGroup默认的generateLayoutParams(ViewGroup.LayoutParams p)实现

protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { 
   
        return p;
}

仅仅是返回了这个不合法的params,这并不是我们期望的,所以这个用法一般是我们重写checkLayoutParams实现合法的校验规则,然后在重写generateLayoutParams创建合法的LayoutParams,看下LinearLayout的实现

@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { 
   
        return p instanceof LinearLayout.LayoutParams;
}
@Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { 
   
        if (sPreserveMarginParamsInLayoutParamConversion) { 
   
            if (lp instanceof LayoutParams) { 
   
                return new LayoutParams((LayoutParams) lp);
            } else if (lp instanceof MarginLayoutParams) { 
   
                return new LayoutParams((MarginLayoutParams) lp);
            }
        }
        return new LayoutParams(lp);
}

前面分析了ViewGroup默认的LayoutParams只是支持layout_width和layout_height属性的,因为它内部只有获取这两个属性的逻辑,但是我们实际很多子View都是需要支持margin属性的,怎么办呢?

ViewGroup还为我们定义了一个MarginLayoutParams,是不是相当的便利

public static class MarginLayoutParams extends ViewGroup.LayoutParams { 
   
        public int leftMargin;
        public int topMargin;
        public int rightMargin;
        public int bottomMargin;
        public MarginLayoutParams(Context c, AttributeSet attrs) { 
   
            super();
            ...//省略若干获取margin属性操作代码
        }

}

所以如果我们需要子View支持margin属性,那么我们就可以重写ViewGroup#generateLayoutParams(AttributeSet attrs)和ViewGroup#generateDefaultLayoutParams()返回MarginLayoutParams

问题来了,我如果还想让子View支持更多的属性呢?那么我们可以自定义LayoutParams继承自MarginLayoutParams,在构造方法中书写获取我们自定义属性的逻辑,同样重写上面两个方法,返回我们自定义的LayoutParams,这样子View就可以获取到了

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/193328.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • velocity调用java静态方法_java模板引擎

    velocity调用java静态方法_java模板引擎跟学习其它技术一样,首先到官网去下载必要的包,下载地址:http://velocity.apache.org/download.cgi目前使用的是velocity1.6.3,由于自己的E文水平一般,在使用之前也到网上搜索了相关文章,然后根据前辈们的指导和自己的实践结合.记录下此文,以便以后能快速回忆.一、在eclipse中新建一个工程,把包velocity-1.6.3.jar到在WEB-INF…

    2022年10月20日
    3
  • 梯度下降 随机梯度下降 算法是_神经网络算法

    梯度下降 随机梯度下降 算法是_神经网络算法一、一维梯度下降算法思想:我们要找到一个函数的谷底,可以通过不断求导,不断逼近,找到一个函数求导后为0,我们就引入了一个概念学习率(也可以叫作步长),因为是不断逼近某个x,所以学习率过大会导致超过最优解,而学习率过小,会导致收敛速度过慢。二、多维梯度下降算法思想:和一维梯度下降算法思想类似,只是导数由原来的一维变成现在的多维,算法思想本质没有变化,在计算导数的过程发生了…

    2025年8月26日
    9
  • jsonobject string转json_发展对象转不了预备党员

    jsonobject string转json_发展对象转不了预备党员用阿里的fastjson里的一个方法,导入fastjson包SONObjectjsonObject1=JSONObject.parseObject(String)

    2022年8月23日
    11
  • Java switch 详解

    Java switch 详解switch语句由一个控制表达式和多个case标签组成。switch控制表达式支持的类型有byte、short、char、int、enum(Java5)、String(Java7)。swi

    2022年7月4日
    22
  • js换行符转换html换行

    js换行符转换html换行js换行符转换html换行在标签中加入:dangerouslySetInnerHTML={{__html:有换行符的数据?.replace(/[\n]/g,“”)}}<divstyle={{float:’right’,width:316,fontSize:14}}dangerouslySetInnerHTML={{__html:有换行符的数据?.replace(/[\n]/g,”<br/>

    2022年5月24日
    63
  • 基于yolov4的目标检测_yolov5预训练模型

    基于yolov4的目标检测_yolov5预训练模型1项目的克隆和必要的环境依赖1.1项目的克隆YOLOv5的代码是开源的,因此我们可以从github上克隆其源码。不得不说GitHub的确是全球最大的男性交友网站,里面的人个个都是人才,yolov5发布才一年左右的时间,YOLOv5就已经更新了5个分支了,分别是yolov5.1-yolov5.5分支。该项目就是利用的yolov5.5分支来作为讲解。首先打开yolov5的github的https://github.com/ultralytics/yolov5/tree…

    2022年8月29日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号