必威体育Betway必威体育官网
当前位置:首页 > IT技术

ConstraintLayout的使用

时间:2019-06-08 04:45:15来源:IT技术作者:seo实验室小编阅读:75次「手机版」
 

layout

ConstraintLayout的诞生,是为了解决我们在平常开发中的复杂多层级布局的问题,在一定程度上进行布局的优化。它有些类似RelativeLayout的功能,都是通过View质之间的相对位置或者View相对于父布局的位置来控制的。但是ConstraintLayout比Relative更加的灵活,方便。而且Android studio提供了ConstaintLayout的可视化编辑工具,可以直接进行拖拽来设置XML的布局。并且在API 2.3(Level 9)以上都可以使用ConstraintLayout。

添加依赖

现在Android studio3.0以上的只要新建Activity的时候生成的默认的xml文件外层布局应该都是ConstraintLayout。如果不是,也没关系,可以使用下面的方法在项目中添加依赖。

1.在对应的project的gradle文件中添加谷歌的仓库依赖maven.google.com

repositories {
    google()
}

2.在对应module下的build.gradle文件中添加下面的依赖(版本可以不同)。

dependencies {
    implementation 'com.android.support.constraint:constraint-layout:1.1.2'
}

重新build之后就可以使用ConstraintLayout了。

创建布局

上面添加依赖成功之后,就可以开始创建我们的布局了。创建布局有两种方式:

1.对原本存在的布局进行修改,如下图所示选择Design,在Component Tree中跟布局点击右键,选择Convert xxx to ContraintLayout。

2.直接创建新的XML文件,直接在Root Tag 上填写 android.support.constraint.ConstraintLayout 就可以创建以ConstraintLayout为跟布局的XML文件了。

ConstraintLayout的使用

对于ConstraintLayout的使用,我其实更喜欢用我们平时喜欢操作XML文件的方式去控制,我觉得这样控制的更加精准,拖拽的方式我这种粗人有的时候一个像素不好调整,当然也可以XML代码操作和拖拽操作相结合的方式。如果大家想学习拖拽的方式来操作ConstraintLayout的话可以看看这篇文章,里面关于拖拽摆放XML写的相当到位清楚了。我这里还是写一些关于XML布局代码相关的操作。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="114dp">
    <View
        android:id="@+id/photo"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:layout_marginTop="10dp"
        android:background="@drawable/bg_about"
        android:scaleType="fitXY"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:text="TextView"
        app:layout_constraintRight_toLeftOf="@id/button"
        app:layout_constraintLeft_toLeftOf="@id/photo"
        app:layout_constraintBottom_toBottomOf="@id/photo"
        app:layout_constraintTop_toTopOf="@id/photo"
        app:layout_constraintHorizontal_chainStyle="packed"/>
    <TextView
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:text="Button\nMkay"
        app:layout_constraintBottom_toBottomOf="@id/photo"
        app:layout_constraintTop_toTopOf="@id/photo"
        app:layout_constraintRight_toRightOf="@id/photo"
        app:layout_constraintLeft_toRightOf="@+id/textView"/>
</android.support.constraint.ConstraintLayout>

上面是一段很简单的代码。放置了一张背景图片还有两个textView 实现的效果就是两个textView居中显示。

在我们平时写的代码中,要想实现这一效果,其实就是相当于将两个TextView放在一起,放入一个LinearLayout或者RelativeLayout中,然后让LinearLayout或者RelativeLayout居中显示,就可以达到两个TextView的组合都居中显示。但是使用ConstraintLayout之后,就可以不需要这外面的一层布局容器就可以达到这个实现效果。这样就减少了布局的层级了。这里先不细讲,先看看我们上面各种app:layout_****的相关属性了,这些属性后面接的都是已经存在的控件的id或者parent。例如上面的 app:layout_constraintLeft_toLeftOf="@id/photo",下面的解释都以后面的值为"@id/photo"为例子的

layout_constraintLeft_toLeftOf      //控件的左边 与photo的左边对其
layout_constraintLeft_toRightOf     //控件的左边 处于id为photo的右边,也就是控件位于photo的右边
layout_constraintRight_toLeftOf     //控件的位于photo控件的左边
layout_constraintRight_toRightOf    //控件的右边与id为photo的控件的右边对其
layout_constraintTop_toTopOf        //控件的顶部与id为photo的控件的顶部对其
layout_constraintTop_toBottomOf     //控件位于id为photo的控件的下边
layout_constraintBottom_toTopOf     //控件位于id为photo的控件的上边
layout_constraintBottom_toBottomOf    //控件的底部与id为photo的控件的底部对其
layout_constraintBaseline_toBaselineOf  //控件的基准线与 id为photo的控件的基准线对其
layout_constraintStart_toEndOf     //和 layout_constraintLeft_toRightOf 类似
layout_constraintStart_toStartOf    //和layout_constraintLeft_toLeftOf 类似
layout_constraintEnd_toStartOf
layout_constraintEnd_toEndOf

其实看上面的解释可以发现一个简单的规律,例如layout_constraintLeft_toLeftOf 这个属性,前面的constraintLeft后面是toLeftOf,这两个值都是left,说明设置的是左边与某个控件的左边对其,也就是只要前后都是设置的left ,right,top,bottom同一个方向值得话,就表示与后面的某个控件的某个方向对其,后面的start,end,baseline都是一个意思。上面的属性都是多个配合使用才能唯一确定位置的。上面的属性只能控制上下左右 开始或者end的位置要具体还可以借助以下几个属性控制精确的位置。

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

和我们平时自己写的类似的margin值意义相同。还有介个比较好玩的属性值

layout_goneMarginStart
layout_goneMarginEnd
layout_goneMarginLeft
layout_goneMarginTop
layout_goneMarginRight
layout_goneMarginBottom

当你所依赖的View的为View.GONE的时候,这些你设置的对应的属性值就会起作用了例如下面的例子:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearLayout2"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        android:text="button1"
        android:visibility="gone"
        />
    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toRightOf="@id/button1"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_goneMarginLeft="20dp"
        android:text="button2"
        />

</android.support.constraint.ConstraintLayout>

上面设置id为button2的Button的左边界处于id为button1的右边,也就是button2在button1的右边,还设置了app:layout_goneMarginLeft="20dp"这个属性,也就是当button1为View.GONE的时候,button2的这个属性值会生效,也就是margintLeft=20dp会生效,当button1为View.VISIBLE或者为View.INVISIBLE的时候这个属性值都会生效。很神奇有木有。其他的属性值同解。

Constraint Demension

和普通的View差不多,在ConstraintLayout容器中的View,它们宽高也有三个可选值:

1.固定尺寸值:就像我们写的20dp,100dp一样,可以给View设置一个固定的宽高值。

2.wrap_content:包裹内容,就是让android系统根据自身的情况去计算View的大小。

3.match_constraint:和我们原来的match_parent有点类似,但是一般不建议使用。直接使用width = "0dp"或者height="0dp"加上left/top/right/bottom属性值为parent可以实现match_constraint的类似match_parent效果。

Ratio 和 Chains

Ratio

Ratio字面意思就是比率,这也是ConstraintLayout区别传统布局容器中一个很好用的属性。

         <Button android:layout_width="wrap_content"
                   android:layout_height="0dp"
                   app:layout_constraintDimensionRatio="1:1" />

例如上面的代码中设置宽度为wrap_content,而app:layout_constraintDimensionRatio="1:1"的设置为1:1,默认情况下,这个属性的值可以写为app:layout_constraintDimensionRatio="0.5" 或者上面的1:1 或者H,1:1 亦或者 W,1:1。下面讲解这个几个数值的意思

app:layout_constraintDimensionRatio="0.5" 也就是控件的宽高比为0.5也就是 w/h = 0.5 高是宽的2倍。

app:layout_constraintDimensionRatio="1:1" 控件的宽高比为1:1,也就是宽和高相等。

app:layout_constraintDimensionRatio="H,3:1"  标识控件的宽高比为3:1也即是 W:H = 3:1

app:layout_constraintDimensionRatio="W,3:1"  标识控件的宽高比为1:3也即是 W:H = 1:3

上面的代码 拷贝到Android studio的xml文件中你会返现宽高比不是1:1,是因为什么原因呢?是因为没有设置位置属性,加上位置相关的属性就可以显示宽高比为1:1了

<Button android:layout_width="100dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintDimensionRatio="1:1" />

Chains

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

创建链条(Creating a chain)

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

链条头(Chain heads)

链条由在链的第一个元素(链的“头”)上设置的属性控制:头是水平链最左边的View,或垂直链最顶端的View。

链的margin(Margins in chains)

先看下面这段代码 和效果就能明白margin的意思了

<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="demo.chain.constraint.com.constraintlayoutdemo.MainActivity">
    <Button
        android:id="@+id/buttonA"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="100dp"
        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="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintLeft_toRightOf="@+id/buttonA"
        app:layout_constraintRight_toRightOf="parent"/>
</android.support.constraint.ConstraintLayout>

     

左边的图片是设置了android:layout_marginLeft="100dp"的效果 右边是去掉这个属性的效果,当我们设置了chains并且制定了某个控件的margin,就相当于整个链条都有了margin值。让后再去根据下面的属性去设置相关的位置。

Chain Style

当在链的第一个元素上设置属性 layout_constraintHorizontal_chainStylelayout_constraintVertical_chainStyle 时,链的行为将根据指定的样式(默认为CHAIN_SPREAD)而更改。style可以取以下几个值:

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

Circular positioning  ,Guideline,Barrier,Group

Circular positioning

我们可以角度和距离 来约束一个控件与另外一个控件的位置关系,可以用下面几个属性控制对应的位置关系:

  • layout_constraintCircle : 后面接控件的id,就是我们以某个控件位中心
  • layout_constraintCircleRadius :   控件之间的距离
  • layout_constraintCircleAngle :   角度

   

<Button android:id="@+id/buttonA" ... />
  <Button android:id="@+id/buttonB" ...
      app:layout_constraintCircle="@+id/buttonA"
      app:layout_constraintCircleRadius="100dp"
      app:layout_constraintCircleAngle="45" />

Guideline

Guideline只能用于ConstraintLayout中,是一个工具类,不会被显示,仅仅用于辅助布局

它可以是horizontal或者 vertical的。(例如:android:orientation="vertical"

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

定位Guideline有三种方式:

  • 指定距离左侧或顶部的固定距离(layout_constraintGuide_begin
  • 指定距离右侧或底部的固定距离(layout_constraintGuide_end
  • 指定在父控件中的宽度或高度的百分比layout_constraintGuide_percent
<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="demo.chain.constraint.com.constraintlayoutdemo.MainActivity">

    <android.support.constraint.Guideline
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/guideline"
        android:orientation="vertical"
        app:layout_constraintGuide_percent="0.5"/>
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="Button"
        app:layout_constraintRight_toLeftOf="@+id/guideline"
        app:layout_constraintTop_toTopOf="parent"
        android:layout_marginStart="40dp"
        android:layout_marginLeft="40dp"/>


</android.support.constraint.ConstraintLayout>

看效果,就好像在整个constrainLayout的中部有一条竖直的分割线,而Button的右边位于guideLine的左边。其他的layout_constraintGuide_begin和layout_constraintGuide_end效果类似可以自己尝试一下。

Barrier

当我们创建布局的时候,有时会遇到布局会随着本地化变化的情况。例如我们 有三个控件A,B,C。A ,内容为22...的控件,B为111....的控件,c为3333....的控件。如果要实现C控件相对于A B控件的右边放置。我们平常的做法就是,将A,B一起放在一个LinearLayout或者RelativeLayout中,然后将C 相对于整个布局容器放置。这就需要为 A ,B 放置一层外层的布局容器。就多了一层布局容器。用Barrier可以减少这一层布局。使得C 控件根据A,B 控件中宽度较大的哪一个 然后靠右,将C 放在宽度较大的哪一个的右边。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/tools"
    xmlns:app2="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="16dp"
        android:text="2222222"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="8dp"
        android:text="1111111"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView1" />

    <android.support.constraint.Barrier
        android:id="@+id/barrier7"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:barrierDirection="end"
        app:constraint_referenced_ids="textView2,textView1" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:text="333333333333333333333333333333333333333333333"
        app:layout_constraintStart_toEndOf="@+id/barrier7"
        app:layout_constraintTop_toTopOf="parent" />
    


</android.support.constraint.ConstraintLayout>

上述代码中 app:layout_constraintStart_toEndOf="@+id/barrier7" 的意思是将TextView3的开始放置在barrier7的右边。Barrier控件和guideline差不多,但是它可以接受多个控件的组合控制。属性  app:barrierDirection="end"。可以有几个其他的值,如下图,很容易理解。就字面意思。

Group

group提供给我们另外一个便利,此类可以控制一组控件的可见性。控件以id标示,多个id之间用逗号隔开。我们可以使用group控制一组控件的可见性。

 <android.support.constraint.Group
              android:id="@+id/group"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:visibility="visible"
              app:constraint_referenced_ids="button4,button9" />

相关阅读

分享到:

栏目导航

推荐阅读

热门阅读