1.Group 1.1版本加入

Group属性用来控制ConstraintLayout布局内,被Group关联的view的可见性。笔者试了一下,是真的只能控制可见性,别的啥也干不了。

android:id="@+id/group"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:visibility="visible"

app:constraint_referenced_ids="button1,button2" />

2.Layer 2.0加入

Layer可以看做是控制它所关联的View从而能形成一个伪边界。为何是伪边界?如下图,Layer可以在关联View后,给Layer设置一个背景。看起来就像寻常的ViewGroup包裹这些View,给ViewGroup设置背景。但是Layer并不是一个ViewGroup,且与它所关联的View处于同一个层级,因此能很好的减少一层布局。

app:layout_constraintBottom_toBottomOf="parent"

app:layout_constraintRight_toRightOf="parent"

android:id="@+id/layer"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:background="@drawable/frame"

android:padding="32dp"

app:constraint_referenced_ids="button4,button5,button3" />

avatar

所以,在不需要对背景做整体View动画如旋转、透明度、位移的情况下,Layer和Group结合可以很好的解决背景和整体可见性的问题,这种场景下,能很大程度的减少View布局嵌套。

3.ConstraintHelper

Group和Layer都是一种Helper,继承于ConstraintHelper,顾名思义,可以看做是View的帮助类,但是ConstraintHelper本身又是继承于View,所以虽然作为Helper,但是可以直接在XML里使用,并使用相关属性和属性API。

观察ConstraintHelper源码:

public abstract class ConstraintHelper extends View {

//helper所关联View id集合

protected int[] mIds = new int[32];

//helper所关联View数量

protected int mCount;

protected Context myContext;

protected Helper mHelperWidget;

protected boolean mUseViewMeasure = false;

protected String mReferenceIds;

//helper所关联View集合

private View[] mViews = null;

private HashMap mMap = new HashMap();

}

那么Helper是如果关联上View进而管理它们的呢?

(1)构造器里调用初始化init()函数

ConstraintLayout_Layout_constraint_referenced_ids通过该属性可以获得Helper所关联的View id串。进而调用setIds,addID等函数,解析出每一个真正的View所对应的id。并id信息存储于mIds等集合中。

protected void init(AttributeSet attrs) {

if (attrs != null) {

TypedArray a = this.getContext().obtainStyledAttributes(attrs, styleable.ConstraintLayout_Layout);

int N = a.getIndexCount();

for(int i = 0; i < N; ++i) {

int attr = a.getIndex(i);

if (attr == styleable.ConstraintLayout_Layout_constraint_referenced_ids) {

this.mReferenceIds = a.getString(attr);

this.setIds(this.mReferenceIds);

}

}

}

}

(2)Helper绘制过程

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

if (this.mUseViewMeasure) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

} else {

this.setMeasuredDimension(0, 0);

}

}

public void onDraw(Canvas canvas) {

}

onMeasure里其实啥也没干,mUseViewMeasure默认为false,因此如果自定义Helper不设置这个值的话,Helper在xml里的宽高并没有影响,也没有任何作用,最终设置进去的都是0。

onDraw里直接是空,Helper虽然是View,但是并没有绘制上的性能损耗。

那么如何使用Helper来帮助我们管理View呢?答案就是在Helper提供的几个updateXX,updateXX与Helper的绘制生命周期所关联,因此自定义的Helper想要达到效果,必须触发绘制过程或者绘制过程的对应阶段。

public void updatePreLayout(ConstraintLayout container) {

}

public void updatePreLayout(ConstraintWidgetContainer container, , Helper helper, SparseArray map

}

public void updatePostLayout(ConstraintLayout container) {

}

public void updatePostMeasure(ConstraintLayout container) {

}

public void updatePostConstraints(ConstraintLayout constainer) {

}

(3)自定义Helper

Group和Layer都是属于一种自定义Helper,均继承与ConstraintHelper。所以再来看它们分别都干了些啥,导致有那些功能的。

Group

public void updatePreLayout(ConstraintLayout container) {

//获得当前Helper的可见属性

int visibility = this.getVisibility();

float elevation = 0.0F;

if (VERSION.SDK_INT >= 21) {

elevation = this.getElevation();

}

if (this.mReferenceIds != null) {

this.setIds(this.mReferenceIds);

}

//遍历关联的View,将helper的可见属性一一赋给它们

for(int i = 0; i < this.mCount; ++i) {

int id = this.mIds[i];

View view = container.getViewById(id);

if (view != null) {

view.setVisibility(visibility);

if (elevation > 0.0F && VERSION.SDK_INT >= 21) {

view.setElevation(elevation);

}

}

}

}

Layer

Layer是如何包裹住关联的View?

public void updatePostLayout(ConstraintLayout container) {

this.reCacheViews();

this.mComputedCenterX = 0.0F / 0.0;

this.mComputedCenterY = 0.0F / 0.0;

LayoutParams params = (LayoutParams)this.getLayoutParams();

ConstraintWidget widget = params.getConstraintWidget();

widget.setWidth(0);

widget.setHeight(0);

//计算Layer中心点的位置

this.calcCenters();

int left = (int)this.mComputedMinX - this.getPaddingLeft();

int top = (int)this.mComputedMinY - this.getPaddingTop();

int right = (int)this.mComputedMaxX + this.getPaddingRight();

int bottom = (int)this.mComputedMaxY + this.getPaddingBottom();

//跟据计算的中间点的位置Layout自身,自此Layer的大小和位置就确定,再设置Background就是顺其自然的事了

this.layout(left, top, right, bottom);

if (!Float.isNaN(this.mGroupRotateAngle)) {

this.transform();

}

}

protected void calcCenters() {

if (this.mContainer != null) {

//Float.isNaN() isNaN->is Not Number 测量一个值是不是科学数字

// 默认mComputedCenterX = 0.0F / 0.0是非法数字

if (this.mNeedBounds || Float.isNaN(this.mComputedCenterX) || Float.isNaN(this.mComputedCenterY)) {

if (!Float.isNaN(this.mRotationCenterX) && !Float.isNaN(this.mRotationCenterY)) {

this.mComputedCenterY = this.mRotationCenterY;

this.mComputedCenterX = this.mRotationCenterX;

} else {

View[] views = this.getViews(this.mContainer);

int minx = views[0].getLeft();

int miny = views[0].getTop();

int maxx = views[0].getRight();

int maxy = views[0].getBottom();

//遍历子View,min值能算出Layer的left和top

//max值能算出layer的right和bottom,不由得感叹真是奇思妙想

for(int i = 0; i < this.mCount; ++i) {

View view = views[i];

minx = Math.min(minx, view.getLeft());

miny = Math.min(miny, view.getTop());

maxx = Math.max(maxx, view.getRight());

maxy = Math.max(maxy, view.getBottom());

}

this.mComputedMaxX = (float)maxx;

this.mComputedMaxY = (float)maxy;

this.mComputedMinX = (float)minx;

this.mComputedMinY = (float)miny;

if (Float.isNaN(this.mRotationCenterX)) {

this.mComputedCenterX = (float)((minx + maxx) / 2);

} else {

this.mComputedCenterX = this.mRotationCenterX;

}

if (Float.isNaN(this.mRotationCenterY)) {

this.mComputedCenterY = (float)((miny + maxy) / 2);

} else {

this.mComputedCenterY = this.mRotationCenterY;

}

}

}

}

}

Layer还支持对关联View的位移、旋转、缩放等操作,但是使用的时候得小心,这些操作的中心点都是基于Layer的中心点

public void setRotation(float angle) {

this.mGroupRotateAngle = angle;

this.transform();

}

public void setScaleX(float scaleX) {

this.mScaleX = scaleX;

this.transform();

}

public void setScaleY(float scaleY) {

this.mScaleY = scaleY;

this.transform();

}

public void setPivotX(float pivotX) {

this.mRotationCenterX = pivotX;

this.transform();

}

public void setPivotY(float pivotY) {

this.mRotationCenterY = pivotY;

this.transform();

}

public void setTranslationX(float dx) {

this.mShiftX = dx;

this.transform();

}

public void setTranslationY(float dy) {

this.mShiftY = dy;

this.transform();

}

private void transform() {

if (this.mContainer != null) {

if (this.mViews == null) {

this.reCacheViews();

}

this.calcCenters();

double rad = Math.toRadians((double)this.mGroupRotateAngle);

//每次操作都会关联位移、缩放、旋转操作叠加效果,因此可以使用Layer对子View整体做一些动画

float sin = (float)Math.sin(rad);

float cos = (float)Math.cos(rad);

float m11 = this.mScaleX * cos;

float m12 = -this.mScaleY * sin;

float m21 = this.mScaleX * sin;

float m22 = this.mScaleY * cos;

for(int i = 0; i < this.mCount; ++i) {

View view = this.mViews[i];

int x = (view.getLeft() + view.getRight()) / 2;

int y = (view.getTop() + view.getBottom()) / 2;

// 默认情况下,mComputedCenterX和mComputedCenterY是Layer的中心点

float dx = (float)x - this.mComputedCenterX;

float dy = (float)y - this.mComputedCenterY;

//小心这里计算出的位移距离是对各种效果的叠加

float shiftx = m11 * dx + m12 * dy - dx + this.mShiftX;

float shifty = m21 * dx + m22 * dy - dy + this.mShiftY;

view.setTranslationX(shiftx);

view.setTranslationY(shifty);

view.setScaleY(this.mScaleY);

view.setScaleX(this.mScaleX);

view.setRotation(this.mGroupRotateAngle);

}

}

}

constraintlayout布局新特性_进阶ConstraintLayout-2.0新特性相关推荐

  1. servlet3.0新特性_查看Servlet 3.0的新增功能

    servlet3.0新特性 随着JEE6规范上市,在企业应用程序领域中如何开发应用程序方面发生了一些重大变化. 在本文中,我将介绍有关Web应用程序开发的一些更改. 首先,请告别web.xml部署描述 ...

  2. .NET2.0和microsoft新知识体系-ASP.NET 2.0新特性

    ASP.NET技术从1.0版本升级到1.1变化不是很大.然而,从ASP.NET 1.x升级到2.0,却不是件轻而易举的事情.ASP.NET 2.0技术增加了大量方便.实用的新特性.图1-1所示列举了A ...

  3. 我的世界java版特性_我的世界Java版特性展望直面会爆料

    在今年我的世界MineconEarth的Java版特性展望直面会上,官方人员曝光了非常多Java版未来会加入的特性,现在就让我们一起来了解一下Java版未来的更新计划吧! [我的世界pc版交流群1]欢 ...

  4. 九州云腾双因素认证系统_“等保2.0”新标准落地 双因子认证(2FA)成标配...

    2019年5月13日,国家标准新闻发布会正式发布网络安全等级保护制度2.0标准(以下简称"等保2.0"),新标准将于2019年12月1日开始实施,这意味着"等保2.0&q ...

  5. constraintlayout布局新特性_安卓ConstraintLayout布局

    layout_constraintLeft_toLeftOf // 左边左对齐 layout_constraintLeft_toRightOf // 左边右对齐 layout_constraintRi ...

  6. HTML中三维特性,前端进阶系列(三):HTML5新特性

    HTML5 是对 HTML 标准的第五次修订.其主要的目标是将互联网语义化,以便更好地被人类和机器阅读,并同时提供更好地支持各种媒体的嵌入.HTML5 的语法是向后兼容的.现在国内普遍说的 H5 是包 ...

  7. mysql数据库的新特性_【数据库】MySQL新特性归档介绍

    MySQL 8.0.17发布了,看了下release note,发现果真如之前预期的那样,恢复了redo log归档(redo log archiving)功能.之所以说是"恢复" ...

  8. ES11新特性_绝对全局对象globalThis---JavaScript_ECMAScript_ES6-ES11新特性工作笔记067

    我们打印一下这个globalThis这个对象去看看,这个是始终指向全局对象的一个系统变量可以直接使用. 可以看到在js中显示是window对象对吧 然后我们在node.js的环境中去试试,可以看到

  9. ES11新特性_可选链操作符---JavaScript_ECMAScript_ES6-ES11新特性工作笔记064

    然后我们去看一下es11提供的这个可选链操作符 可以看到如果我们有个main方法,然后有个config参数 然后我们调用这个main方法 然后写入,db和cache,传入这个对象. 然后我们之前调用的 ...

  10. ES10新特性_字符串扩展方法_trimStart--trimEnd---JavaScript_ECMAScript_ES6-ES11新特性工作笔记058

    我们来看一下,在es10中,还引入了,trimStart--trimEnd 分别用来清除一个字符串的左侧的空白和,右侧的空白,超级简单,不多说了. 技术交流QQ群[JAVA,C++,Python,.N ...

最新文章

  1. Java-并发-LockSynchronized
  2. apache评分表的意义_APACHE评分系统及评分表
  3. openssl 开启AES-NI指令集性能增加
  4. Windows2003使用WEB方式修改域用户密码
  5. 使用DLL封装窗体和业务类
  6. js 根据固定位置获取经纬度--腾讯地图
  7. 算法题存档20190127
  8. 苹果和谷歌在印度下架数十款中国应用;贾跃亭宣布破产重组完成;Tails 4.8 发布| 极客头条...
  9. 怎么用sql按条件把表分离_在做sqlserver数据库sql优化时,这25条事项需要注意
  10. 社交网络分析算法(SNA)
  11. 腾讯云TRTC —— 实时音视频完整案例 音视频+共享屏幕直播
  12. RB女歌手宇西个人单曲《盛宴》上线 诠释独自疗伤的故事
  13. 真香!有了这个搜索大法,GitHub玩到飞起来!
  14. python标准库复数运算包cmath
  15. 原型模式——java实现原型模式的几种写法
  16. 100句正能量的句子经典语句
  17. (trigger)触发器的定义和作用
  18. jmeter 察看结果树
  19. 三种常用的嵌入式操作系统
  20. DELL机器不能安装一键还原精灵装机版的解决方法(已解决)

热门文章

  1. 论文阅读-可变形卷积网络:Deformable Convolutional Networks
  2. 图像语义分割(15)-ConvCRFs:用于语义分割的卷积条件随机场
  3. ajax跨域请求jsonp
  4. OOAD-1 GOF中的23种设计模式的分类和功能
  5. python内置类型详细解释
  6. JS-两个空数组为什么不相等?
  7. 字符串格式参数的日期比较函数
  8. OpenCV单目视觉定位(测量)系统
  9. 【linux系统学习笔记】Ubuntu文本界面和图像界面的切换
  10. leetcode刷题日记-三个无重叠子数组的最大和