每日一问:LayoutParams 你知道多少?

前面的文章中着重讲解了 View 的测量流程。其中我提到了一句非常重要的话:**View 的测量匡高是由父控件的 MeasureSpec 和 View 自身的 `LayoutParams 共同决定的。**我们在前面的 每日一问:谈谈对 MeasureSpec 的理解 把 MeasureSpec 的重点进行了讲解,其实另外一个 LayoutParams 同样是非常非常重要。

从概念讲起

LayoutParams,顾名思义,就是布局参数。而且大多数人对此都是司空见惯,我们 XML 文件里面的每一个 View 都会接触到 layout_xxx 这样的属性,这实际上就是对布局参数的描述。大概大家也就清楚了,layout_ 这样开头的东西都不属于 View,而是控制具体显示在哪里。

LayoutParams 都有哪些初始化方法

通常来说,我们都会把我们的控件放在 XML 文件中,即使我们有时候需要对屏幕做比较「取巧」的适配,会直接通过 View.getLayoutParams() 这样的方法获取 LayoutParams 的实例,但我们接触的少并不代表它的初始化方法不重要。

实际上,用代码写出来的 View 加载效率要比在 XML 中加载快上大约 1 倍。只是在如今手机配置都比较高的情况下,我们常常忽略了这种方式。

我们来看看 ViewGroup.LayoutParams 到底有哪些构造方法。

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;
}LayoutParams() {  }
复制代码

MarginLayoutParams

除去最后一个放给 MarginLayoutParams 做处理的方法外,我们在 ViewGroup 中还有 3 个构造方法。他们分别负责给 XML 处理、直接让用户指定宽高、还有类似集合的 addAll() 这样的方式的赋值方法。

实际上,ViewGroup 的子类的 LayoutParams 类拥有更多的构造方法,感兴趣的自己翻阅源码查看。在这里我想更加强调一下我上面提到的 MarginLayoutParams

MarginLayoutParams 继承于 ViewGroup.LayoutParams

public static class MarginLayoutParams extends ViewGroup.LayoutParams {@ViewDebug.ExportedProperty(category = "layout")public int leftMargin;@ViewDebug.ExportedProperty(category = "layout")public int topMargin;@ViewDebug.ExportedProperty(category = "layout")public int rightMargin;@ViewDebug.ExportedProperty(category = "layout")public int bottomMargin;@ViewDebug.ExportedProperty(category = "layout")private int startMargin = DEFAULT_MARGIN_RELATIVE;@ViewDebug.ExportedProperty(category = "layout")private int endMargin = DEFAULT_MARGIN_RELATIVE;public MarginLayoutParams(Context c, AttributeSet attrs) {super();TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);setBaseAttributes(a,R.styleable.ViewGroup_MarginLayout_layout_width,R.styleable.ViewGroup_MarginLayout_layout_height);int margin = a.getDimensionPixelSize(com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);if (margin >= 0) {leftMargin = margin;topMargin = margin;rightMargin= margin;bottomMargin = margin;} else {int horizontalMargin = a.getDimensionPixelSize(R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);// ... something}// ... something}
}
复制代码

一看代码,自然就清楚了,为什么我们以前会发现在 XML 布局里, layout_margin 属性的值会覆盖 layout_marginLeftlayout_marginRight 等属性的值。

实际上,事实上,绝大部分容器控件都是直接继承 ViewGroup.MarginLayoutParams 而非 ViewGroup.LayoutParams。所以我们再自定义 LayoutParams 的时候记得继承 ViewGroup.MarginLayoutParams

在代码里面使用 LayoutParams

前面介绍了 LayoutParams 的几种构造方法,我们下面以 LinearLayout.LayoutParams 来看看几种简单的使用方式。

val textView1 = TextView(this)
textView1.text = "不指定 LayoutParams"
layout.addView(textView1)val textView2 = TextView(this)
textView2.text = "手动指定 LayoutParams"
textView2.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT)
layout.addView(textView2)val textView3 = TextView(this)
textView3.text = "手动传递 LayoutParams"
textView3.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams(100, 100))
layout.addView(textView3)
复制代码

我们看看 addView() 都做了什么。

public void addView(View child) {addView(child, -1);
}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);
}@Override
protected LayoutParams generateDefaultLayoutParams() {if (mOrientation == HORIZONTAL) {return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);} else if (mOrientation == VERTICAL) {return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);}return null;
}public void addView(View child, int index, LayoutParams params) {if (DBG) {System.out.println(this + " addView");}if (child == null) {throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");}requestLayout();invalidate(true);addViewInner(child, index, params, false);
}private void addViewInner(View child, int index, LayoutParams params,boolean preventRequestLayout) {// ...if (!checkLayoutParams(params)) {params = generateLayoutParams(params);}// ...
}@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {return p instanceof LinearLayout.LayoutParams;
}
复制代码

看起来 ViewGroup 真是煞费苦心,如果我们没有给 View 设置 LayoutParams,则系统会帮我们根据 orientation 设置默认的 LayoutParams。甚至是我们即使在 addView() 之前设置了错误的 LayoutParams 值,系统也会我们帮我们进行纠正。

虽然系统已经做的足够完善,帮我们各种矫正错误,但在 addView() 之后,我们还强行设置错误的 LayoutParams,那还是一定会报 ClassCastException 的。

LayoutParams 很重要,每一名 Android 开发都应该尽力地去掌握,只有弄清楚了系统的编写方式,应对上面类似简书的流式布局才能更好处理。

实际上 Google 出的 FlexboxLayout 已经做的相当完美。 当然如果使用的 RecyclerView,还可以自己写一个 FlowLayoutManager 进行处理。

原文较多地参考自:blog.csdn.net/yisizhu/art…

转载于:https://juejin.im/post/5d00f3a6f265da1bb003b7f8

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/387600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kuangbin专题十六 KMP扩展KMP HDU2594 Simpsons’ Hidden Talents

Homer: Marge, I just figured out a way to discover some of the talents we weren’t aware we had. Marge: Yeah, what is it? Homer: Take me for example. I want to find out if I have a talent in politics, OK? Marge: OK. Homer: So I take some politician’s na…

SNI: 实现多域名虚拟主机的SSL/TLS认证

为什么80%的码农都做不了架构师?>>> 一. 介绍 早期的SSLv2根据经典的公钥基础设施PKI(Public Key Infrastructure)设计,它默认认为:一台服务器(或者说一个IP)只会提供一个服务,所以在SSL握手时…

echo(),print(),print_r(),var_dump()的区别

echo可以一次输出多个值,多个值之间用逗号分隔。echo是语言结构(language construct),而并不是真正的函数,因此不能作为表达式的一部分使用。echo是php的内部指令,不是函数,无返回值。 print():函数print()…

我心目中的牛程序员、我们可以对比看看(人家还是看多年朋友面子上才肯帮忙1周,至少需支付1万元辛苦费)...

为什么80%的码农都做不了架构师?>>> 最近碰到客户整个网站改版的需要,非常短的时间里只有1周时间里,需要把整个B2C网站彻底的进行版面,我自己估算了一下,就是往死里干一天工作48个小时,1周也干…

c#做端口转发程序支持正向连接和反向链接

3389的时候 例子1:连接a机器的3389端口连不上,因为对方防火墙或者网关做了限制,只能访问a机器的个别端口比如80。 例子2:连接a机器的几乎所有端口都连不上(对方乃内网或者防火墙网关做了限制)&#xff0c…

Spring Boot(十四):spring boot整合shiro-登录认证和权限管理

Spring Boot(十四):spring boot整合shiro-登录认证和权限管理 使用Spring Boot集成Apache Shiro。安全应该是互联网公司的一道生命线,几乎任何的公司都会涉及到这方面的需求。在Java领域一般有Spring Security、Apache Shiro等安全框架,但是由…

通用权限管理系统组件 (GPM - General Permissions Manager) 不改数据库、甚至不写代码就集成铜墙铁壁权限管理组件...

为什么80%的码农都做不了架构师?>>> 越成熟的东西,越牛X的东西,越简单才对,简单才是硬道理,苹果的手机只有少数几个按键,苹果Ipad也很少的按钮,甚至连苹果的笔记本键盘都少一排&…

数学符号及读法大全

数学符号及读法大全 常用数学输入符号: ≈ ≡ ≠ = ≤≥ < > ≮ ≯ ∷ + - / ∫ ∮ ∝ ∞ ∧ ∨ ∑ ∏ ∪ ∩ ∈ ∵ ∴ ⊥ ‖ ∠ ⌒ ≌ ∽ √ () 【】&#xff5b…

在使用win 7 无线承载网络时,启动该服务时,有时会提示:组或资源的状态不是执行请求操作的正确状态。 网上有文章指出,解决这个问题的方法是在设备管理器中启动“Microsoft托管网络虚拟适配

在使用win 7 无线承载网络时,启动该服务时,有时会提示:组或资源的状态不是执行请求操作的正确状态。 网上有文章指出,解决这个问题的方法是在设备管理器中启动“Microsoft托管网络虚拟适配器”,见 http://jingyan.baid…

阿里一年,聊聊我成长了什么,入职阿里的职业生涯感悟

2018.5.31~2019.5.31,一段精彩的旅程,渡过了在阿里一年的时光,这段时光有快乐、有焦虑、有迷茫、更有思考,思考的是自己过去的种种不足、思考的是一些现在看来之前错误的想法、思考的是如何成为一个更好的技术人,将这一…

偏差-方差分解(转)

1、定义 这里所说的偏差-方差分解就是一种解释模型泛化性能的一种工具。它是对模型的期望泛化错误率进行拆解。 样本可能出现噪声,使得收集到的数据样本中的有的类别与实际真实类别不相符。对测试样本 x,另 yd 为 x 在数据集中的标记,y 为真实…

用过C#的朋友可能认为它是一种十分安全的语言,其实C#也可以做到经典的缓冲区溢出。 本文章将用一个实例来描述C#究竟是如何发生缓冲区溢出的! 首先建立一个C# Console工程,并开启工程的“允许

用过C#的朋友可能认为它是一种十分安全的语言,其实C#也可以做到经典的缓冲区溢出。 本文章将用一个实例来描述C#究竟是如何发生缓冲区溢出的! 首先建立一个C# Console工程,并开启工程的“允许不安全代码”选项 键入代码: [csharp]…

COOKIE伪造登录网站后台

1.关于XSS(跨站脚本攻击)和CSRF(跨站请求伪造)的知识,xss表示Cross Site Scripting(跨站脚本攻击),它与SQL注入攻击类似,SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除…

Spring Cloud 学习 (五) Zuul

Zuul 作为路由网关组件,在微服务架构中有着非常重要的作用,主要体现在以下 6 个方面: Zuul, Ribbon 以及 Eureka 相结合,可以实现智能路由和负载均衡的功能,Zuul 能够将请求流量按某种策略分发到集群状态的多个服务实例…

如何利用445端口进行入侵渗透 445端口入侵原因详细解析。大家在进行入侵渗透个人电脑的时候,经常会碰到各种各样的端口,比如135,1433,445,3306等端口,现在小编就给大家讲解下445端口如

如何利用445端口进行入侵渗透 445端口入侵原因详细解析。大家在进行入侵渗透个人电脑的时候,经常会碰到各种各样的端口,比如135,1433,445,3306等端口,现在小编就给大家讲解下445端口如何入侵。 445端口入侵…

项目复盘

前言 最近一年半多一直在做一个CMS项目,做了快两年了也没有上线,而且开发还走了不少,其中有不少原因是因为开发中频繁改动需求导致开发人员失去耐心,但是其中还有一个重要的原因就是架构设计的不好,导致很多服务的边界…

父、子页面之间页面元素的获取,方法的调用

一、在iframe页面上调取父级页面元素 1.在父页面上获取iframe页面元素(在父页面修改子页面div的背景色为红色) js代码如下&#xff1a; 1 <script type"text/javascript"> 2 window.onload function(){ 3 var iframe document.getElementById(iframeId)…

fiddler,他和其他抓包软件有什么区别,如何使用fiddler进行抓包

前言&#xff1a;本文章是搭配《批量获取微信公众号》一文&#xff0c;介于群里朋友很热情&#xff0c;我就趁着上班测完bug 来撰写该文章&#xff0c;那么读完本文&#xff0c;你会学习到什么呢&#xff1f; 什么是fiddler&#xff0c;他和其他抓包软件有什么区别&#xff0c…

Vue导入非模块化的第三方插件功能无效解决方案

一、问题&#xff1a; 最近在写vue项目时&#xff0c;想引入某些非模块化的第三方插件时&#xff0c;总是发现会有报错。且在与本地运行插件测试对比时发现插件根本没有注入到jQuery中&#xff08;console.log($.fn)查看当前jq有哪些方法&#xff09;&#xff0c;例如&#xff…

ES6笔记 -- 字符串拓展

字符串拓展 Unicode 相关 JS 允许使用/uxxxx的Unicode方式显示字符, 但是只限于码点在/u0000~/uFFFF之间, 超过该范围的码点必须用双字节形式表示ES6 中, 将码点放入大括号内, 就可以解读JS 不能处理4个字节的字符, 字符串长度会被误判为2ES6 提供了codePointAt方法, 能够正确处…