美文网首页
Android - 一个 item 布局带你领略 Constra

Android - 一个 item 布局带你领略 Constra

作者: 拾识物者 | 来源:发表于2019-04-09 14:45 被阅读0次

    本文是 ConstraintLayout 小课堂系列第 1 讲,课程目录:

    1. 一个 item 布局带你领略 ConstraintLayout 的魅力
    2. ConstraintLayout Chain 链布局能干啥

    布局要求

    先上最终效果图:

    1. 这是一个 Item 布局,分为两行,第一行显示可变长度的文字,第二行显示固定长度的文字,底部还有一个粗线条条。
    2. 绿色背景的文字语义上是一个标签,可以不显示,也就是设置 visibility=gone,这时右侧的长文字要占据整个宽度。
    3. 长文字与标签的间距是 10dp,而标签距离 parent 的间距是 16dp,隐藏掉标签后长文字要左移占据标签的位置,距离 parent 要保持 16dp 的间距。
    4. 上下两行的高度是固定的 40dp,行内文字垂直居中对齐。

    实现思路

    首先要找到布局的起点,然后创建其他 View 与起点的关系,一点一点将所有 View 放在正确的位置。

    整个布局被分成上下两行,并且两行都是固定高度,内部的 View 在行内居中。可以用两个 ConstraintLayout 的 Guideline 来固定在行的中间位置,通过居中对齐的方式将 View 与 Guideline 对齐。

    详解

    如何居中布局

    ConstraintLayout 并不是靠一个单独的属性设置居中,而是用两侧的约束像弹簧一样将 View 拉起来浮在中间。

    垂直居中需要将 layout_height 设置为 wrap_content,然后上下两个边界设置为同一个对象:Bottom_toBottomOfTop_toTopOf。同理水平居中需要设置 layout_widthStart_toStartOfEnd_toEndOf

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal" 👉 水平线还是垂直线
        app:layout_constraintGuide_begin="20dp" /> 👉 begin 表示距 parent top 多长
    <TextView
        android:id="@+id/title"
        android:layout_height="wrap_content" 👉 重点,居中必须设置为 wrap_content
        app:layout_constraintBottom_toBottomOf="@+id/guideline" 👉 两边都要设置才能居中
        app:layout_constraintTop_toTopOf="@+id/guideline" 👉 两边都要设置才能居中
        ... />
    

    如何用约束设置尺寸

    layout_wdithlayout_height 设置为 0dp 表示匹配约束的含义。下面是长文字设置为匹配剩余宽度的代码:

    <TextView
        android:id="@+id/title"
        android:layout_width="0dp" 👉 重点,匹配约束必须“放弃宽度”,设置为 0dp
        android:layout_marginStart="10dp"
        android:layout_marginEnd="10dp"
        android:ellipsize="end" 👉 末尾显示 ... 
        android:lines="1" 👉 只显示一行,防止撑大高度
        android:text="Update 3rd libs, and submit app for review."
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/tag" />
    

    居中与匹配约束两种布局,一个是保持 View 原有尺寸放置在中间,一个是拉伸 View 直到符合约束。其实约束相关的属性设置是一样的,不一样的是尺寸属性,layout_widthlayout_height,设置的值是 wrap_content 还是 0dp

    Guideline 是一条水平线或者垂直线,可设置距离 ConstraintLayout 边缘的大小,在约束布局中可以像普通 View 一样用来定义关系。本例中用来当做垂直居中对齐的锚点。

    如何对齐文字的 Baseline

    垂直对齐除了 top 和 bottom 以外,还有 baseline,只对含有文字的 View 生效,比如 TextView,表示两个 TextView 的文字基准对齐,获得更美观的排版效果。

    <TextView
            android:id="@+id/tag"
            android:text="iOS app"
            app:layout_constraintBaseline_toBaselineOf="@+id/title" 👉 baseline 对齐
            ... />
    

    如何处理 GONE 了的 View

    神奇的 ConstraintLayout 完全可以自动处理 visibility=gone 的 View。处理的规则是:

    • 这个 View 被缩小为一个尺寸为 0×0 的点。
    • 这个 View 的 margins 值都会变成 0。
    • 与其他 View 之间的约束仍然生效。
    <TextView
        android:id="@+id/tag"
        android:visibility="gone" 👉 消失了
        android:layout_marginStart="16dp" 
        ... />
    <TextView
        android:id="@+id/title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        app:layout_constraintStart_toEndOf="@+id/tag" 👉 tag消失了,我贴上来
         />
    

    按照规则,TextView(tag) 的宽度变为 0,并且 margin 变为 0,于是 TextView(title) 被拉伸到了左边与 parent 左对齐,这时候与 parent 的左边距是它自己的 layout_marginStart="10dp"

    结果与设计不符了,这时候就要使用一组神奇的属性:goneMargin:layout_goneMarginStartlayout_goneMarginBottom 等等。表示如果我通过约束连接了一个 gone View,我这个方向上的 margin 由 goneMargin 属性替代。

    因此这里添加一下 goneMargin 属性就达到了想要的效果:

    <TextView
        android:id="@+id/title"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        app:layout_constraintStart_toEndOf="@+id/tag"
        👇 constraintStart 指向的 View gone 了,于是 goneMarginStart 说了算了
        app:layout_goneMarginStart="16dp" 
         />
    

    本节课程内容小节

    • 如何居中布局
    • 如何用约束设置尺寸
    • 如何对齐文字的 Baseline
    • 如何处理 GONE 了的 View

    全部代码

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.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">
    
        <View
            android:id="@+id/first_line"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:background="#0099aa"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:layout_editor_absoluteX="0dp"
            tools:layout_editor_absoluteY="0dp" />
    
        <View
            android:id="@+id/second_line"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:background="#992277"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/first_line"
            tools:layout_editor_absoluteX="0dp"
            tools:layout_editor_absoluteY="0dp" />
    
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_begin="20dp" />
    
        <TextView
            android:id="@+id/tag"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:background="#009000"
            android:padding="6dp"
            android:text="iOS app"
            android:textColor="@android:color/white"
            android:textSize="14sp"
            android:visibility="gone"
            app:layout_constraintBaseline_toBaselineOf="@+id/title"
            app:layout_constraintStart_toStartOf="parent" />
    
        <TextView
            android:id="@+id/title"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginEnd="10dp"
            android:ellipsize="end"
            android:lines="1"
            android:text="Update 3rd libs, and submit app for review."
            android:textSize="17sp"
            app:layout_constraintBottom_toBottomOf="@+id/guideline"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/tag"
            app:layout_constraintTop_toTopOf="@+id/guideline"
            app:layout_goneMarginStart="16dp" />
    
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guideline2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_begin="60dp" />
    
        <TextView
            android:id="@+id/startTime"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="16dp"
            android:layout_marginTop="27dp"
            android:text="13:10"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/guideline2"
            app:layout_constraintBottom_toBottomOf="@+id/guideline2" />
    
        <TextView
            android:id="@+id/connector"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:text="-"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintStart_toEndOf="@+id/startTime"
            app:layout_constraintTop_toTopOf="@+id/startTime" />
    
        <TextView
            android:id="@+id/separator"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="145dp"
            android:text="|"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@+id/startTime" />
    
        <TextView
            android:id="@+id/endTime"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:text="16:15"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintStart_toEndOf="@+id/connector"
            app:layout_constraintTop_toTopOf="@+id/startTime" />
    
        <TextView
            android:id="@+id/interval"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:text="03:05"
            android:textSize="18sp"
            android:textStyle="bold"
            app:layout_constraintStart_toEndOf="@+id/separator"
            app:layout_constraintTop_toTopOf="@+id/startTime" />
    
        <View
            android:id="@+id/colorBar"
            android:layout_width="100dp"
            android:layout_height="6dp"
            android:layout_marginTop="14dp"
            android:background="#009900"
            app:layout_constraintLeft_toLeftOf="@+id/interval"
            app:layout_constraintTop_toBottomOf="@+id/guideline2" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    (ole)

    相关文章

      网友评论

          本文标题:Android - 一个 item 布局带你领略 Constra

          本文链接:https://www.haomeiwen.com/subject/frzmiqtx.html