ConstraintLayout

 

部分转:ConstraintLayout 属性详解 和Chain的使用

 

  • layout_constraintLeft_toLeftOf --左侧靠xxx控件的左侧
  • layout_constraintLeft_toRightOf --左侧靠xxx控件的右侧
  • layout_constraintRight_toLeftOf --右侧靠xxx控件的左侧 
  • layout_constraintRight_toRightOf --右侧靠xxx控件的右侧 
  • layout_constraintTop_toTopOf --顶部靠xxx控件的顶部
  • layout_constraintTop_toBottomOf --顶部靠xxx控件的下部
  • layout_constraintBottom_toTopOf --底部靠xxx控件的顶部 
  • layout_constraintBottom_toBottomOf --底部靠xxx控件的底部
  • layout_constraintBaseline_toBaselineOf --这个地方我们下面会专门分析下,灰常有意思(网络有些都是直接翻译官方,没怎么解释这个东东)
  • 下面这个几种单独使用上效果和上面的有几个很像,具体有什么区别呢?按照我了解的以前relativelayout的layout_toRightOf和layout_toEndOf的区别,说的是新版的是toEndOf,官方建议使用toEndOf。难道是为了兼容旧版的才搞了两套? 后面有发现再专门补上吧....
  • layout_constraintStart_toEndOf --起始边和终止边对齐
  • layout_constraintStart_toStartOf -- 起始边和起始边对齐
  • layout_constraintEnd_toStartOf --终止边和起始边对齐
  • layout_constraintEnd_toEndOf --终止边和终止边对齐
  • 父布局记得都是android.support.constraint.ConstraintLayout哟哟哟

2.1.1 一个一个来,也有可能一次多个一起实践,看下左左右右,上上下下的解析图

画了画图,应该能看懂...嗯。

这几个比较简单,自己尝试下就行了。和以前RealaoutLayout的alignparent相关属性差不多。

这几种组合基本能够满足控件之间简单的相对位置的布局了。有些像left靠right的布局有时候也是有需求的,比如你开始就是让它再屏幕外面,之后你有可能你会做一个动画平移过来,然后回去,灵活运用就好了!

最后我们说下layout_constraintBaseline_toBaselineOf 

首先是基本的布局使用,button6再button1的右下角。然后我们有定义了一个与button6同样高度的按钮button7,靠button6的右边。

 

 

然后我们加上

 

你会发现:

 

 

 

 

间距 Margins


android:layout_marginStart
android:layout_marginEnd
android:layout_marginLeft
android:layout_marginTop
android:layout_marginRight
android:layout_marginBottom

注意只能设值正值或0

layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom

当约束id组件gone时的间距
同样负值也无效

 

 

 

 

 偏移 Centering positioning

layout_constraintHorizontal_bias
layout_constraintVertical_bias

如以下代码

app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="@+id/secondTag"

在左右方向都设置约束时 左右相对的间距百分比,默认为0.5
app:layout_constraintHorizontal_bias="0.3"则左边间距占0.3 右边间距0.7

圆形定位 Circular Positioning

当一个View需要根据另一个View进行定位时,该角度和距离是从两个视图的中心点测量的。就像以某种角度和距离围绕行星旋转的卫星。

circular positon

被约束的View可以对齐到相对于其中心View的任何角度和半径

  • app:layout_constraintCircle—对齐于哪个View
  • app:layout_constraintCircleAngle—对齐的角度
  • app:layout_constraintCircleRadius —对齐View的距离(半径)

 

对可见性的处理(Visibility behavior)

这一节是对前一节goneMargin的补充。
重点是Gone隐藏掉的控件,会被解析成一个点,并忽略margin。

ConstraintLayout能为View.GoneView特殊处理。
通常,GONE的控件不会被显示,并且不是布局本身的一部分(即如果标记为GONE,则其实际尺寸并不会更改)。
但是在布局计算方面,GONE的View仍然是其中的一个重要区别:
对于布局传递,它们的维度将被视为零(基本上它们将被解析为一个点
如果他们对其他小部件有约束力,那么他们仍然会受到尊重,但任何margin都将等于零

 


注意A的margin也被忽略了。

 

拿上个Demo改一下,为A 加上一个android:layout_marginRight="10dp"
为了使A 隐藏后,B仍能纹丝不动,则B的app:layout_goneMarginRight="120dp"
B goneMarginRight120 = A宽度100 + A marginRight10 +B marginRight10

    <Button
        android:id="@+id/button4"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        android:text="button4"
        app:layout_constraintRight_toRightOf="parent"
        />
    <Button
        android:id="@+id/button5"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        android:text="button5"
        app:layout_constraintRight_toLeftOf="@id/button4"
        app:layout_goneMarginRight="120dp"/>

尺寸约束(Dimensions constraints)

ConstraintLayout的最小尺寸 (Minimum dimensions on ConstraintLayout)

可以为ConstraintLayout自身定义最小的尺寸,他会在 ConstraintLayoutWRAP_CONTENT时起作用。
● android:minWidth
● android:minHeight 

控件尺寸约束(Widgets dimension constraints)

控件的宽高有三种方式为其设置:

  • 确定尺寸
  • WRAP_CONTENT
  • 0dp,就等于MATCH_CONSTRAINT

有些人可能有疑问,为什么不用MATCH_PARENT了。
官方文档如是说:

MATCH_PARENT is not supported for widgets contained in a ConstraintLayout, though similar behavior can be defined by using MATCH_CONSTRAINT with the corresponding left/right or top/bottom constraints being set to "parent".

意思是MATCH_PARENT不再被支持了,通过MATCH_CONSTRAINT替代。
我们写个Demo看一下三种方式设置的效果吧:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    ...
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:text="Button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/button10"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintLeft_toLeftOf="@+id/button"
        app:layout_constraintRight_toRightOf="@+id/button"
        app:layout_constraintTop_toBottomOf="@+id/button"/>

    <Button
        android:id="@+id/button11"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintLeft_toLeftOf="@+id/button10"
        app:layout_constraintRight_toRightOf="@+id/button10"
        app:layout_constraintTop_toBottomOf="@+id/button10"/>

</android.support.constraint.ConstraintLayout>

效果如图:

 


有些人是不是要说,你特么逗我,不是说好的0dp等于MATCH_CONSTRAINT,应该是撑满屏幕的呀,
OK ,把刀放下。让我们仔细看这个MATCH_CONSTRAINT属性。它match的是约束。
而这里第三个按钮的约束是第二个按钮,所以它的宽度设置为MATCH_CONSTRAINT时,是和它的约束按钮,即第二个按钮一样宽。
注意,此时,竖直方向上没有约束,所以不能使用MATCH_CONSTRAINT属性.

 

我们仅仅将第三个按钮的属性修改为

        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"

则它宽度会撑满屏幕:

 

 

我们再修改Demo,分别为后两个按钮加上margin:

<android.support.constraint.ConstraintLayout
    ...
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:layout_width="200dp"
        android:layout_height="100dp"
        android:text="Button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <Button
        android:id="@+id/button10"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintLeft_toLeftOf="@+id/button"
        app:layout_constraintRight_toRightOf="@+id/button"
        app:layout_constraintTop_toBottomOf="@+id/button"/>


    <Button
        android:id="@+id/button12"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        app:layout_constraintLeft_toLeftOf="@id/button10"
        app:layout_constraintRight_toRightOf="@id/button10"
        app:layout_constraintTop_toBottomOf="@id/button10"/>

    <Button
        android:id="@+id/button11"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginRight="10dp"
        android:text="Button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button12"/>

</android.support.constraint.ConstraintLayout>

效果如图:

 

 

最后,记住一句话约束要和 0dp 的 方向一致。否则无效

比例(Ratio)

只有一个方向约束:

可以以比例去定义View的宽高
为了做到这一点,需要将至少一个约束维度设置为0dp(即MATCH_CONSTRAINT
并将属性layout_constraintDimentionRatio设置为给定的比例。

例如:

    <Button
        android:layout_width="200dp"
        android:layout_height="0dp"
        android:text="Ratio"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="2:1"
        app:layout_constraintTop_toTopOf="parent"/>

如图:

 

 

比例值有两种取值:

  • 浮点值,表示宽度和高度之间的比率 (2,0.5)
  • “width:height”形式的比例 (5:1,1:5)

当约束多于一个(宽高都被约束了)

如果两个维度均设置为MATCH_CONSTRAINT(0dp),也可以使用比例。 在这种情况下,系统会使用满足所有约束条件和比率的最大尺寸
如果需要根据一个维度的尺寸去约束另一个维度的尺寸。
则可以在比率值的前面添加 W 或者 H 来分别约束宽度或者高度

例如,如果一个尺寸被两个目标约束(比如宽度为0,在父容器中居中),可以使用 W 或H 来指定哪个维度被约束。

    <Button
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="H,2:1"
        app:layout_constraintTop_toTopOf="parent"/>

这里用“H”表示以高度为约束,高度的最大尺寸就是父控件的高度,“2:1”表示高:宽 = 2 : 1.
则宽度为高度的一半:

 

 

链条(Chains)

链条在同一个轴上(水平或者垂直)提供一个类似群组的统一表现。另一个轴可以单独控制。

创建链条(Creating a chain)

如果一组小部件通过双向连接(见图,显示最小的链,带有两个小部件),则将其视为链条。

 

 

链条头(Chain heads)

链条由在链的第一个元素(链的“头”)上设置的属性控制:


头是水平链最左边的View,或垂直链最顶端的View。

 

链的margin(Margins in chains)

如果在连接上指定了边距,则将被考虑在内。
例如

    <Button
        android:id="@+id/buttonA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="50dp"
        android:text="Button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/buttonB"/>

    <Button
        android:id="@+id/buttonB"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintLeft_toRightOf="@+id/buttonA"
        app:layout_constraintRight_toRightOf="parent"/>

通过app:layout_constraintRight_toLeftOf="@+id/buttonB"app:layout_constraintLeft_toRightOf="@+id/buttonA"就建立了链条,(我中有你,你中有我)。
然后它们两个成了一个整体,所以链条左边设置app:layout_constraintLeft_toLeftOf="parent"使得和父控件左对齐,
右边设置app:layout_constraintRight_toRightOf="parent"使得和父控件右对齐,
这样整个链条就居中了,最后对左控件设置了margin,相当于整个链条左边有了margin
效果:

 

 

链条样式(Chain Style)

当在链的第一个元素上设置属性 layout_constraintHorizontal_chainStylelayout_constraintVertical_chainStyle时,链的行为将根据指定的样式(默认为CHAIN_SPREAD)而更改。
看图这里就很像JS里的flexible有木有。因为ConstraintLayout就是模仿flexible做的。

 


取值如下:

 

  • spread- 元素将被展开(默认样式)
  • 加权链 - 在spread模式下,如果某些小部件设置为MATCH_CONSTRAINT,则它们将拆分可用空间
  • spread_inside- 类似,但链的端点将不会扩展
  • packed- 链的元素将被打包在一起。 孩子的水平或垂直偏差属性将影响包装元素的定位

拿加权链举个例子:

    <Button
        android:id="@+id/buttonA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="50dp"
        android:text="Button"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/buttonB"/>

    <Button
        android:id="@+id/buttonB"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintLeft_toRightOf="@+id/buttonA"
        app:layout_constraintRight_toRightOf="parent"/>

 

 

加权链(Weighted chains)

LinearLayout的weight类似。

链的默认行为是在可用空间中平均分配元素。 如果一个或多个元素使用MATCH_CONSTRAINT,它们将使用剩余的空白空间(在它们之间相等)。 属性layout_constraintHorizontal_weightlayout_constraintVertical_weight将决定这些都设置了MATCH_CONSTRAINT的View如何分配空间。 例如,在包含使用MATCH_CONSTRAINT的两个元素的链上,第一个元素使用权重为2,第二个元素的权重为1,第一个元素占用的空间将是第二个元素的两倍

最后关于链条,再给大家看一个关于margin的demo:

    <Button
        android:id="@+id/buttonA"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="50dp"
        android:text="Button"
        app:layout_constraintHorizontal_chainStyle="spread"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/buttonB"/>

    <Button
        android:id="@+id/buttonB"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintLeft_toRightOf="@+id/buttonA"
        app:layout_constraintRight_toRightOf="parent"/>

 


一图胜千言,可以看到虽然他们的weight相等,但是margin是被计算在约束里的,所以左边的按钮宽度比右边的小。

 


Guideline

Guideline只能用于ConstraintLayout中,是一个工具类,不会被显示,仅仅用于辅助布局
它可以是horizontal或者 vertical的。(例如:android:orientation="vertical"

  • verticalGuideline宽度为零,高度为ConstraintLayout的高度
  • horizontalGuideline高度为零,宽度为ConstraintLayout的高度

定位Guideline有三种方式:

  • 指定距离左侧或顶部的固定距离(layout_constraintGuide_begin
  • 指定距离右侧或底部的固定距离(layout_constraintGuide_end
  • 指定在父控件中的宽度或高度的百分比layout_constraintGuide_percent

一个栗子一看便知:

<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">

    <android.support.constraint.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="100dp"/>

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Button"
        app:layout_constraintLeft_toLeftOf="@+id/guideline"
        app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

预览:

 

 

Guideline源码:

public class Guideline extends View {
    public Guideline(Context context) {
        super(context);
        super.setVisibility(8);
    }
    public Guideline(Context context, AttributeSet attrs) {
        super(context, attrs);
        super.setVisibility(8);
    }
    public Guideline(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        super.setVisibility(8);
    }
    public Guideline(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr);
        super.setVisibility(8);
    }
    public void setVisibility(int visibility) {
    }
    public void draw(Canvas canvas) {
    }
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        this.setMeasuredDimension(0, 0);
    }
}
public static final int GONE = 0x00000008;

源码就这么点,这货的源码和ViewStub有点像啊,可以看出

  • 它默认是GONE的。8 就是View.GONE的值。
  • 它的public void setVisibility(int visibility)方法被空实现了,所以用户也没办法改变它的可见度。
  • 推导出它一定是GONE的。在屏幕上不可见
  • this.setMeasuredDimension(0, 0);public void draw(Canvas canvas)的空实现,表明这是一个超轻量的View,不可见,没有宽高,也不绘制任何东西。仅仅作为我们的锚点使用。

 

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值