我平时项目开发必备框架html
译为"约束布局", 是Google在AndroidStudio2.2引入的布局. 在AndroidStudio 2.3直接替代了以前的Activity建立的默认布局RelativeLayout. 能够看到Google对其重视性.java
特色android
本文实时更新测试版最新特性git
官方文档github
最新依赖版本bash
dependencies { compile 'com.android.support.constraint:constraint-layout:1.1.1' } 复制代码
ConstraintLayout是至今对AndroidStudio的布局编辑器支持最好的布局.markdown
布局编辑器左边有个面板, 用于拖控件到布局编辑器中网络
在布局编辑器的左边就是所有的控件列表. 能够经过直接拖动到布局预览界面来建立视图控件. 而且不须要你手动导入依赖包.app
依次介绍:框架
顺序依次
预览图主要显示手机的实际效果(ConstraintLayout拥有布局编辑器属性, 因此存在预览界面和实际应用不一样的状况), 蓝图主要清晰显示布局的信息
二者均可以直接编辑布局, 看你的喜爱.
ConstraintLayout布局属性
这一栏是根据你选择的ViewGroup变化的布局属性栏, 这里我只介绍ConstraintLayout的布局属性栏, 其余的没什么好介绍的一看就知道了.
依次功能:
这个相似磁铁的图标若是处于开启状态. 控件只要一拖到布局编辑器中就会自动建立水平和垂直方向各一条约束.
该功能属于一次性功能, 点击一次就会自动计算而且给当前布局编辑器中全部没有进行约束处理的控件进行水平和垂直方向各一条约束.
ConstraintLayout能够配合一些"辅助控件"使用
辅助线用户是不可见的, 也没有宽高参数(你给他设置也无效). 只是在约束布局中作一个相对基准线而已.
<android.support.constraint.Guideline android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/guideline2" android:orientation="vertical" app:layout_constraintGuide_percent="0.41" /> 复制代码
辅助线有三种属性
app:layout_constraintGuide_begin="20dp" app:layout_constraintGuide_end="340dp" app:layout_constraintGuide_percent="0.055555556" 复制代码
辅助线有水平和垂直两种:
障碍物, 分为垂直和水平(相似GuidLine).
使用场景:当两个文本并排时右侧有一个按钮, 可是两个文本可能长度都是不肯定的包裹类型. 把任何一个文本做为按钮的约束均可能致使按钮覆盖住另外一个文本内容. 这个时候就须要Barriers.
Barrier控件可使用属性来同时约束多个控件
app:constraint_referenced_ids="tv_1,tv_2"
复制代码
而后经过属性指定在控件的方向
app:barrierDirection="right" 复制代码
right和left等于垂直
bottom和top等于水平
int[] getReferencedIds() int getType() void setReferencedIds(int[] ids) void setType(int type) 复制代码
组是Constraintlayout 1.1x版本增长的辅助工具, 目的在于同时分组控制多个控件的Visibility
属性.
xml属性
app:constraint_referenced_ids="tv_1,tv_2"
复制代码
java方法
int[] getReferencedIds() void setReferencedIds(int[] ids) 复制代码
经过以上属性将多个控件的id填入, 就能够同时控制多个控件的隐藏和显示
示例:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.jiuxing.constraintlayout.MainActivity"> <TextView android:id="@+id/tv_1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/tv_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="64dp" android:layout_marginEnd="60dp" android:text="TextView" app:layout_constraintBottom_toTopOf="@+id/tv_1" app:layout_constraintEnd_toEndOf="parent" /> <android.support.constraint.Group android:id="@+id/group" android:layout_width="151dp" android:layout_height="126dp" android:layout_marginEnd="192dp" android:visibility="gone" android:layout_marginTop="24dp" android:background="@color/colorAccent" app:constraint_referenced_ids="tv_1,tv_2" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout> 复制代码
Tip: 设置背景颜色并不影响Group组内控件颜色. 只单单是Visibility属性.
使用场景: 某些状况你可能须要控制多个控件同步显示或者隐藏, 在数据未加载成功时不少视图不该该显示给用户(加载中布局)
占位控件; 经过不断地setContent
来替换视图内容;
示例:
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.jiuxing.constraintlayout.MainActivity"> <android.support.constraint.Placeholder android:id="@+id/placeholder" android:layout_width="50dp" android:layout_height="50dp" android:layout_marginStart="64dp" android:layout_marginTop="48dp" app:content="@+id/iv" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/iv" android:layout_width="200dp" android:layout_height="100dp" android:src="@color/colorAccent" /> </android.support.constraint.ConstraintLayout> 复制代码
PlaceHolder之因此强大在于同时也提供代码设置内容id
// 设置内容视图 View getContent() void setContentId(int id) 复制代码
若是PlaceHolder没有设置内容那么一样想显示怎么办
// 设置空 void setEmptyVisibility(int visibility) int getEmptyVisibility() 复制代码
示例:
要求在建立视图的时候就设置好, 不然后面设置无效(例如在onCreate方法中就设置)
place.setEmptyVisibility(View.VISIBLE);
复制代码
涉及到三个属性
app:layout_constraintCircle="@id/btn_invoke" <!--圆心控件--> app:layout_constraintCircleRadius="100dp" <!--圆形半径大小--> app:layout_constraintCircleAngle="80" <!--圆形的角度--> 复制代码
示例:
<Button android:id="@+id/btn_invoke" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="24dp" android:onClick="invoke" android:text="执行" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> <Button android:id="@+id/btn_2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="51dp" android:layout_marginTop="31dp" android:text="2" app:layout_constraintCircle="@id/btn_invoke" app:layout_constraintCircleRadius="100dp" app:layout_constraintCircleAngle="80" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" /> 复制代码
效果图:
在1.1以前若是布局属性是wrap_content
将没法遵照约束, 这一问题如今能够经过如下属性修复了;
app:layout_constrainedWidth=”true”
复制代码
说到Percent Dimensions就不得不说ConstraintLayout中的0dp问题,当控件设置为0dp的时候(0dp的称呼又叫match_constraint),默认的行为是撑开(spread),占满可用空间,可是这个行为是能够用layout_constraintWidth_default 属性来设置的。在 ConstraintLayout 1.0.x中,这个属性还能够把它设置为wrap。而到了1.1.x,它又有了一个新的值:percent,容许咱们设置控件占据可用空间的百分比。
下面的TextView控件将占据剩余宽度的50%和剩余高度的50%。
<TextView android:id="@+id/textView6" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintHeight_default="percent" app:layout_constraintHeight_percent="0.5" app:layout_constraintWidth_default="percent" app:layout_constraintWidth_percent="0.5" /> 复制代码
除了布局编辑器写布局也应该要了解布局的属性, 否则有些问题你看不出来的.
该属性并不会在Android上有任何影响, 只会影响AS的布局编辑器坐标
tools:layout_editor_absoluteY="246dp" tools:layout_editor_absoluteX="36dp" 复制代码
布局编辑器
真机上
一个控件有四个约束点/ 十二个约束属性(左和右有各有两个属性start和end以及right和left)
约束只能是同一水平下才能相互约束, 例如左和右之间能约束, 左不能和上下约束点关联.
约束并非相互关联的关系. 而是
// 和父布局关联约束 app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" // 和其余控件关联约束 app:layout_constraintLeft_toRightOf="@+id/button3" app:layout_constraintRight_toLeftOf="@+id/button3" app:layout_constraintTop_toBottomOf="@id/button3" app:layout_constraintBottom_toTopOf="@id/button3" layout_constraintStart_toEndOf layout_constraintStart_toStartOf layout_constraintEnd_toStartOf layout_constraintEnd_toEndOf 复制代码
有些控件是包含文字内容的, 因此约束布局的控件有一个文字基准线约束. 默认是隐藏,须要点击开关显示.
layout_constraintBaseline_toBaselineOf
复制代码
注意: 使用了文字基准线对齐就不须要使用上下约束了
经过小数点(百分比)控制控件在屏幕垂直/水平的百分比位置.
注意: 只有水平位置(上下/左右约束点都添加了约束)都添加约束, 该控件才支持百分比偏移
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintVertical_bias="0.69" 复制代码
注意: 若是是约束的ConstraintLayout, 不须要这两个属性也能够设置百分比偏移
通常的边距没什么好讲的. 和之前同样.
android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom
复制代码
由于约束布局控件以前的关联性太强, 若是一个布局隐藏(gone)就可能致使整个布局的位置移动. 因此ConstraintLayout拥有隐藏边距属性
ConstraintLayout中使用Gone属性值
根据官方图能够看出Constraintlayout若是控件被隐藏并不会像其余布局同样坐标变成0,0点. 只是margin和宽高变成0.
layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom
复制代码
以上边距属性会根据其约束的控件是不是隐藏(invisible不算)来生效, 同时margin失效.
经过设置宽或者高中的一个为match_constraint(0dp), 就能够设置控件的宽高比
matc_constraint的宽或高会根据另外一边的尺寸变化来符合比例
宽高比分两种:
宽:高
app:layout_constraintDimensionRatio="2:1" 复制代码
很简单就是宽比高, 默认受约束的就是match_constraint(0dp)
的一边.
受约束的会根据另外一边发生尺寸比例的变化(若是是match_constraint和wrap_content时1:1比例会发生尺寸变化成正方形)
自定义
app:layout_constraintDimensionRatio="w,2:1" 复制代码
我理解为颠倒了比例. w即设置比例为高比宽, h为宽比高. 实际操做体验吧
宽高属性值
理论上ConstraintLayout的宽高再也不使用match_parent
这一属性值. 取而代之的是0dp(称为match_constraint).
**Important: **
MATCH_PARENT
is not supported for widgets contained in aConstraintLayout
, though similar behavior can be defined by usingMATCH_CONSTRAINT
with the corresponding left/right or top/bottom constraints being set to"parent"
.
官方说明match_parent在ConstraintLayout中不被支持
match_constraint只有在水平或者垂直拥有两条方向的约束时才有效, 即匹配剩余所有空间. 若是只有水平只存在一条或者没有约束至关于wrap_content.
示例图:
若是你强行使用编辑器会自动帮你转换成固定dp值, 不过若是你仅仅是约束ConstraintLayout布局并无问题.不能理解我说的什么本身动手试试.
两个空间相互约束就会产生一个锁链. (注意布局编辑器中是没法经过拖动约束点相互约束, 我认为是bug)
只能经过多选居中的方式或者直接XML编辑.
app:layout_constraintHorizontal_chainStyle="packed" 复制代码
连接在一块儿主要是能够设置不一样的样式达到适配父容器宽度或者高度的效果. 注: 一个链还有第一个控件才须要设置(chainStyle)样式.
根据样式有三种参数值:
官方有一张介绍图
虽然看着有五个,实际上属性仍是那三个. 不过有加入权重和百分比偏移. Bias是偏移, weighted是权重.
和LinearLayout的wight属性同样. 不过只支持spread和spread_inside有效.
layout_constraintHorizontal_weight
复制代码
一样能够编辑属性也能够鼠标修改
wrap_content
不受约束的限制 (这一问题在ConstraintLayout1.1被解决)
app:layout_constrainedWidth=”true|false”
app:layout_constrainedHeight=”true|false”
复制代码
须要知道的是,当咱们使用 MATCH_CONSTRAINT 时,ConstraintLayout 将不得不对控件进行 2 次测量,而测量的操做是昂贵的。
而优化器(Optimizer)的做用就是对 ConstraintLayout 进行优化,对应设置给 ConstraintLauyout 的属性是:
可设置的值有:
在设置值时,能够设置多个,如:
app:layout_optimizationLevel="direct|barrier|dimensions" 复制代码
修改ConstraintLayout官方不推荐使用ConstraintLayout.LayoutParams
而是推荐使用ConstraintSet
ConstraintSet
能够直接经过代码建立或改变约束/改变Margin等操做, 而且都提供方法而非成员变量.
若是你想修改ConstraintLayout中任意一个控件的属性都须要进行如下三个步骤.
步骤:
示例:
public class MainActivity extends AppCompatActivity { ConstraintSet mConstraintSet = new ConstraintSet(); // create a Constraint Set ConstraintLayout mConstraintLayout; // cache the ConstraintLayout @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.state1); Context context = this; mConstraintLayout = (ConstraintLayout) findViewById(R.id.activity_main); mConstraintSet.clone(mConstraintLayout); // 克隆一个布局到ConstraintSet } public void onClick(View view) { TransitionManager.beginDelayedTransition(mConstraintLayout); // 一行代码添加动画 mConstraintSet1.applyTo(mConstraintLayout); // 应用到新的布局 } } 复制代码
官方示例, 可是我发现我是无效.
复制一个ConstraintLayout布局到ConstraintSet中. 后面能够对ConstraintSet进行修改(即对复制的布局修改).
void clone (ConstraintSet set) void clone (ConstraintLayout constraintLayout) void clone (Context context, int constraintLayoutId) 复制代码
这仅仅指的是建立一条约束, 一个控件能够存在n条约束. 最少两条才能肯定位置.
须要注意的是START
和LEFT
自己是能够并存的. 不要混用
void connect(int startID, int startSide, int endID, int endSide) void connect(int startID, int startSide, int endID, int endSide, int margin) 复制代码
示例:
// 克隆布局 mConstraintSet = new ConstraintSet(); mConstraintSet.clone(mBinding.root); // 用三条约束链接两个控件 mConstraintSet.connect(R.id.btn_3, ConstraintSet.LEFT, R.id.btn, ConstraintSet.RIGHT, 100); mConstraintSet.connect(R.id.btn_3, ConstraintSet.TOP, R.id.btn, ConstraintSet.TOP); mConstraintSet.connect(R.id.btn_3, ConstraintSet.BOTTOM, R.id.btn, ConstraintSet.BOTTOM); // 应用布局 mConstraintSet.applyTo(mBinding.root); 复制代码
void centerVertically(int viewId, int toView) void centerVertically(int centerID, int topId, int topSide, int topMargin, int bottomId, int bottomSide, int bottomMargin, float bias) 复制代码
示例: 相对父布局垂直居中
mConstraintSet.centerVertically(R.id.btn_3, ConstraintSet.PARENT_ID);
复制代码
相对其余控件垂直居中
mConstraintSet.centerVertically(R.id.btn_3, R.id.btn);
复制代码
错误示例: 若是你使用TOP或者BOTTOM之类的属性, 只会贴靠顶部.. 并不会居中
mConstraintSet.centerVertically(R.id.btn_3, ConstraintSet.TOP);
复制代码
注意若是你在第二种方法垂直居中使用了LEFT或RIGHT会致使程序中止
水平居中一样不能使用TOP或者BOTTOM, 而且Rtl和不包含Rtl有使用上的区别
void centerHorizontally(int centerID, int leftId, int leftSide, int leftMargin, int rightId, int rightSide, int rightMargin, float bias) void centerHorizontally(int viewId, int toView) // 只能使用LEFT/RIGHT 否者Crash void centerHorizontallyRtl(int viewId, int toView) void centerHorizontallyRtl(int centerID, int startId, int startSide, int startMargin, int endId, int endSide, int endMargin, float bias) // 只能使用START/END 复制代码
示例:
// 居中父布局 mConstraintSet.centerHorizontallyRtl(R.id.btn_3, ConstraintSet.PARENT_ID); mConstraintSet.centerHorizontallyRtl(R.id.btn_3, R.id.btn, ConstraintSet.START, 0, R.id.btn_2, ConstraintSet.END, 0, 0.5f); 复制代码
该方法不只支持水平居中还支持垂直居中.
void center (int centerID, int firstID, int firstSide, int firstMargin, int secondId, int secondSide, int secondMargin, float bias) 复制代码
能够是一个像素值尺寸或者 WRAP_CONTENT
或MATCH_CONSTRAINT
void constrainHeight (int viewId, int height) // 像素单位 void constrainWidth (int viewId, int width) 复制代码
最大和最小宽高只在MATCH_CONSTRAINT
状况下才有效果
void constrainMaxHeight (int viewId, int height) void constrainMinHeight (int viewId, int height) void constrainMaxWidth (int viewId, int width) void constrainMinWidth (int viewId, int width) 复制代码
默认宽高: 即均布排列的时候宽度(例如weight模式下)
void constrainDefaultWidth (int viewId, int width) void constrainDefaultWidth (int viewId, int width) 复制代码
建立Guideline
void create (int guidelineID, // 给建立的guideline指定id int orientation) // guidline方向 复制代码
设置Guideline边距
void setGuidelineEnd (int guidelineID, int margin) void setGuidelineBegin (int guidelineID, int margin) void setGuidelinePercent (int guidelineID, float ratio) 复制代码
void createBarrier (int id, // id int direction, // 方向 int... referenced) // 组id 复制代码
设置类型
void setBarrierType (int id, int type) 复制代码
void clear (int viewId, int anchor) // 删除该空间某一约束 void clear (int viewId) // 删除该控件所有约束 复制代码
示例: 删除顶部约束
mConstraintSet.clear(R.id.btn, ConstraintSet.TOP);
复制代码
void setAlpha (int viewId, float alpha) 复制代码
旋转中心是控件的中心
void setRotation (int viewId, float rotation) // 以控件的左上角为中心旋转 void setRotationX (int viewId, float rotationX) // 以控件的x轴翻转 void setRotationY (int viewId, float rotationY) // 以控件的y轴翻转 复制代码
以控件为中心, 百分比浮点数
void setScaleX (int viewId, float scaleX) // 倍数关系 void setScaleY (int viewId, float scaleY) 复制代码
以控件中心偏移
void setTranslation (int viewId, float translationX, float translationY) void setTranslationX (int viewId, float translationX) void setTranslationY (int viewId, float translationY) void setTranslationZ (int viewId, float translationZ) // z轴偏移必须在大于21才有效 复制代码
void setMargin (int viewId, int anchor, int value) 复制代码
示例:
mConstraintSet.setMargin(R.id.btn, ConstraintSet.TOP, 200); 复制代码
若是想要百分比生效必须同时设置两边约束(例如左右或者上下)
void setHorizontalBias (int viewId, float bias) void setVerticalBias (int viewId, float bias) 复制代码
将当前ConstraintSet实例中Clone的ConstraintLayout应用到一个ConstraintLayout布局中. 因为你是经过clone()
方法来建立的ConstraintSet因此若是不使用apply()
并不会改变clone的ConstraintLayout.
void applyTo (ConstraintLayout constraintLayout) 复制代码
不用Clone直接加载一个XML布局文件.
void load (Context context, int resourceId) 复制代码
主要介绍一些多是Bug或者是我知识层面不够的问题
若是你使用了infer Constraint会发现自动生成了不少以tools开头的属性, 这些属性不用去管, 不对应用有任何影响.
tools:layout_constraintTop_creator="1" 复制代码
主要是由于控件存在两个左右边距属性(start和left或者right和end)
删除start或者end便可. 我的认为是bug, 已经提交给Google.(个人推荐是所有都是用START和END)
要想使用Chain两个控件必须相互约束, 可是布局编辑器中没法相互约束
可是XML直接编辑或者如下方法仍是能够相互约束的, 因此我的认为是bug
若是出现控件不在编辑器内显示, 请检查编辑器属性坐标.
tools:layout_editor_absoluteX="137dp" tools:layout_editor_absoluteY="-118dp" 复制代码