前言
前面两天学习了控件使用,今天开始学习布局。
1.LinearLayout 线性布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:gravity="center_horizontal"
android:divider="@drawable/my_divider"
android:showDividers="middle"
android:dividerPadding="30dp"
>
<LinearLayout
android:layout_width="100dp"
android:layout_height="0dp"
android:background="@color/black"
android:layout_weight="2"
></LinearLayout>
<LinearLayout
android:layout_width="100dp"
android:layout_height="0dp"
android:background="#ff332b"
android:layout_weight="1"
></LinearLayout>
<LinearLayout
android:layout_width="100dp"
android:layout_height="0dp"
android:background="#004422"
android:layout_weight="1"
></LinearLayout>
<LinearLayout
android:layout_width="100dp"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#666666"
android:layout_gravity="left"
></LinearLayout>
</LinearLayout>
UI效果,weight权重建议设置高度或者宽度为0dp结合使用,以及权重的方向是跟随LinearLayout的Orientation的,这点要注意一下。
2.RelativeLayout 相对布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:id="@+id/red_rl"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#ff332b"
android:layout_alignParentRight="true"
xmlns:android="http://schemas.android.com/apk/res/android">
</RelativeLayout>
<RelativeLayout
android:id="@+id/other_rl"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#666666"
android:layout_below="@id/red_rl"
xmlns:android="http://schemas.android.com/apk/res/android" >
</RelativeLayout>
</RelativeLayout>
UI预览效果
3.FrameLayout 帧布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<FrameLayout
android:layout_height="400dp"
android:layout_width="400dp"
android:background="#ffff00"
xmlns:android="http://schemas.android.com/apk/res/android">
</FrameLayout>
<FrameLayout
android:layout_height="300dp"
android:layout_width="300dp"
android:background="#ff332b"
android:foreground="@drawable/ceshi1"
android:foregroundGravity="right|bottom"
xmlns:android="http://schemas.android.com/apk/res/android">
</FrameLayout>
<FrameLayout
android:layout_height="200dp"
android:layout_width="200dp"
android:background="#00ff00"
xmlns:android="http://schemas.android.com/apk/res/android">
</FrameLayout>
</FrameLayout>
UI实际效果
4.TableLayout 列表布局
<?xml version="1.0" encoding="utf-8"?>
<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stretchColumns="1"
xmlns:android="http://schemas.android.com/apk/res/android">
<TableRow>
<Button android:text="按钮" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<Button android:text="按钮" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<Button android:text="按钮" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<Button android:text="按钮" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
</TableRow>
<TableRow>
<Button android:text="按钮" android:layout_width="wrap_content" android:layout_height="wrap_content" ></Button>
<Button android:text="按钮" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
</TableRow>
<TableRow>
<Button android:text="按钮" android:layout_width="wrap_content" android:layout_height="wrap_content"></Button>
<Button android:text="按钮" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_column="3"></Button>
</TableRow>
<TableRow>
<Button android:text="按钮" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_span="3"></Button>
</TableRow>
</TableLayout>
实际效果
GridLayout 网格布局
和TableLayout比较相似,但是TableLayout无法将多行合并
Orientation为horizontal时,使用columnCount去限制. Orientation为Vertical时,使用RowCount去限制.
<?xml version="1.0" encoding="utf-8"?>
<GridLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:columnCount="4"
xmlns:android="http://schemas.android.com/apk/res/android">
<Button
android:text="按钮"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
<Button
android:text="按钮"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
<Button
android:text="按钮"
android:layout_width="wrap_content"
android:layout_columnWeight="1"
android:layout_height="wrap_content">
</Button>
<Button
android:text="按钮"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
<Button
android:text="按钮"
android:layout_row="1"
android:layout_column="1"
android:layout_rowWeight="1"
android:layout_columnSpan="2"
android:layout_gravity="fill"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</Button>
</GridLayout>
要注意的是columnSpan和rowSpan是需要结合layout_gravity才能实现跨多行或跨多列.
5.ContraintLayout 约束布局
使用起来非常类似XCode的StoryBoard的约束设置。
此处内容部分引用来自
通过拖动圆圈设置约束,适合简单界面的时候使用,复杂页面的时候拖拽控件容易导致约束对照错误的问题,建议还是手写XML代码实现。
相关属性分为八大类
1.自身的属性
-
android_maxHeight 最大高度
-
android_maxWidth 最大宽度
-
android_minHeight 最小高度
-
android_minWidth 最小宽度
2.相对定位
| 属性 | 含义 |
|---|---|
| layout_constraintStart_toStartOf | 约束左边与谁的左边对齐 |
| layout_constraintStart_toEndOf | 约束左边在谁的右边 |
| layout_constraintEnd_toStartOf | 约束右边在谁的左边 |
| layout_constraintEnd_toEndOf | 约束右边与谁对齐 |
| layout_constraintTop_toTopOf | 约束顶部与谁对齐 |
| layout_constraintTop_toBottomOf | 约束顶部在谁的底部 |
| layout_constraintBottom_toTopOf | 约束底部在谁的顶部 |
| layout_constraintBottom_toBottomOf | 约束底部与谁对齐 |
| layout_constraintBaseline_toBaselineOf | 约束基线与谁对齐 |
| 下图是 |
每个 View 的上下左右以及 baseline 示意图:
3.GuideLine使用的属性
- android_orientation 控制 Guideline 是横向的还是纵向的
- layout_constraintGuide_begin 控制 Guideline 距离父容器开始的距离
- layout_constraintGuide_end 控制 Guideline 距离父容器末尾的距离
- layout_constraintGuide_percent 控制 Guideline 在父容器中的位置为百分比
4.Margin
如果没有 Margin 则两个 View 会紧紧挨着,比如上面的 ButtonB 和 ButtonA 挨着。而很多情况下,设计的效果都要求 View 之间有间隔,这个时候就要使用 Margin 属性了。
下图为 Margin 的说明:
下面为控制 View margin 的属性:
- layout_marginStart
- layout_marginEnd
- layout_marginLeft
- layout_marginTop
- layout_marginRight
- layout_marginBottom
margin 值只能为大于等于0的数字,这些都是很常见的属性,不做详细介绍了。
而下面 6 个是控制当前 View 所参考的 View 状态为 GONE 的时候的 margin 值:
- layout_goneMarginBottom
- layout_goneMarginEnd
- layout_goneMarginLeft
- layout_goneMarginRight
- layout_goneMarginStart
- layout_goneMarginTop
5.居中和偏移
- layout_constraintHorizontal_Bias
- layout_constraintVertical_Bias
这两个属性需要结合左右边或者上下边的约束使用。效果为两边的权重分配
上图设置了水平bias为0.3,垂直bias为0.7
<Button
android:text="button"
android:id="@+id/button5"
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintVertical_bias="0.7"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
>
</Button>
6.子View的尺寸控制
ConstraintLayout 中子 View 的宽度和高度还是通过 android:layout_width 和 android:layout_height 来指定,可以有三种不同的取值:
– 使用确定的尺寸,比如 48dp
– 使用 WRAP_CONTENT ,和其他地方的 WRAP_CONTENT 一样
– 使用 0dp,这个选项等于 “MATCH_CONSTRAINT”,也就是和约束规则指定的宽(高)度一样
例如下图:
(a) 设置为wrap_content;(b) 设置为 0dp,则 View 的宽度为整个父容器的宽度;(c) 是设置了 margin的情况下的宽度。
注意: MATCH_PARENT 属性无法在 ConstraintLayout 里面的 子 View 上使用。
控制子 View 的宽高比
-
layout_constraintDimensionRatio 控制子View的宽高比
除了上面三种设置 子 View 的尺寸以外,还可以控制 子 View 的宽高比。如果要使用宽高比则需要至少设置一个尺寸约束为 0dp,然后设置 layout_constraintDimentionRatio 属性:
-
<Button android:layout_width="wrap_content" android:layout_height="0dp" app:layout_constraintDimensionRatio="1:1" />上面的代码会设置 Button 的高度和宽度一样。
比率的取值有两种形式:
– float 值,代表宽度/高度 的比率
– “宽度:高度”这种比率值如果宽度和高度都是 MATCH_CONSTRAINT (0dp) 也可以使用宽高比。这种情况,系统会使用满足所有约束条件和比率的最大尺寸。要根据其中一种尺寸来约束另外一种尺寸,则可以在比率值的前面添加 W 或者 H来分别约束宽度或者高度。例如,如果一个尺寸被两个目标约束(比如宽度为0dp,在父容器中居中),你通过使用字符 W 或者 H 来指定那个边被约束。
例如:<Button android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintDimensionRatio="H,16:9" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent"/>上面的 layout_constraintDimensionRatio 取值为 H,16:9,前面的 H 表明约束高度,所以结果就是 Button 的宽度和父容器宽度一样,而高度值符合 16:9 的比率。
除了基本的 View 尺寸控制以为,还有如下几个精细控制 View 尺寸的属性(注意:下面这些属性只有宽度或者高度设置为 0dp (MATCH_CONSTRAINT) 的情况下才有效):
-
layout_constraintWidth_default
-
layout_constraintHeight_default 取值为 spread 或者 wrap,默认值为 spread ,占用所有的符合约束的空间;如果取值为 Wrap ,并且view 的尺寸设置为 wrap_content 且受所设置的约束限制其尺寸,则 这个 view 最终尺寸不会超出约束的范围。
-
下图为各个取值的示意图:
-
layout_constraintHeight_max 取值为具体的尺寸
-
layout_constraintHeight_min 取值为具体的尺寸
-
layout_constraintWidth_max 取值为具体的尺寸
-
layout_constraintWidth_min 取值为具体的尺寸
-
下图为各个取值的示意图:
-
-
7、链条布局(Chains)
Chains 为同一个方向(水平或者垂直)上的多个子 View 提供一个类似群组的概念。其他的方向则可以单独控制。
创建一个 Chain
多个 View 相互在同一个方向上双向引用就创建了一个 Chain。什么是双向引用呢? 比如在水平方向上两个 Button A 和 B,如果 A 的右边位于 B 的左边,而 B 的左边位于 A 的右边,则就是一个双向引用。如下图:
-
-
注意: 在 Android Studio 编辑器中,先把多个 View 单向引用,然后用鼠标扩选多个 View,然后在上面点击右键菜单,选择 “Center Horizontally” 或者 “Center Vertically” 也可以快速的创建 Chain。
-
Chain heads
Chain 的属性由该群组的第一个 View 上的属性所控制(第一个 View 被称之为 Chain head).
-
-
水平群组,最左边的 View 为 head, 垂直群组最上面的 View 为 head。
Margins in chains
可以为 Chain 中的每个子 View 单独设置 Margin。对于 spread chains, 可用的布局空白空间是扣除 margin 后的空间。下面会详细解释。
Chain Style
下面几个属性是控制 Chain Style 的:
-
layout_constraintHorizontal_chainStyle
-
layout_constraintHorizontal_weight
-
layout_constraintVertical_chainStyle
-
layout_constraintVertical_weight
chainStyle 是设置到 Chain Head 上的,指定不同的 style 会改变里面所有 View 的布局方式,有如下四种 Style:
-
CHAIN_SPREAD 这个是默认的 Style, 里面的所有 View 会分散开布局
-
Weighted chain,在 CHAIN_SPREAD 模式下,如果有些 View 的尺寸设置为 MATCH_CONSTRAINT(0dp),则这些 View 尺寸会占据所有剩余可用的空间,和 LinearLayout weight 类似。
-
下面是几种模式示意图:
-
CHAIN_SPREAD_INSIDE 和 CHAIN_SPREAD 类似,只不过两端的两个 View 和 父容器直接不占用多余空间,多余空间在 子 View 之间分散
-
CHAIN_PACKED 这种模式下,所有的子 View 都 居中聚集在一起,但是可以设置 bias 属性来控制聚集的位置。
-
下面是几种模式示意图:
-
-
如果多个子View尺寸设置为 MATCH_CONSTRAINT(0dp),则这些 View 会平均的占用多余的空间。通过 layout_constraintXXX_weight 属性,可以控制每个 View 所占用的多余空间的比例。例如,对于只有两个 View 的一个水平 Chain,如果每个View 的宽度都设置为 MATCH_CONSTRAINT, 第一个 View 的 weight 为 2;第二个 View 的 weight 为 1,则第一个 View 所占用的空间是 第二个 View 的两倍。
8、UI 编辑器所使用的属性
下面几个属性是 UI 编辑器所使用的,用了辅助拖拽布局的,在实际使用过程中,可以不用关心这些属性。
-
layout_optimizationLevel
-
layout_editor_absoluteX
-
layout_editor_absoluteY
-
layout_constraintBaseline_creator
-
layout_constraintTop_creator
-
layout_constraintRight_creator
-
layout_constraintLeft_creator
Guideline
Guideline 是 ConstraintLayout 中一个特殊的辅助布局的类。相当于一个不可见的 View,使用 ConstraintLayout 可以创建水平或者垂直的参考线,其他的 View 可以相对于这个参考线来布局。
-
垂直 Guideline 的宽度为 0, 高度为 父容器(ConstraintLayout)的高度
-
水平 Guideline 的高度为 0, 宽度为 父容器(ConstraintLayout)的宽度
-
参考线的位置是可以移动的。
-
layout_constraintGuide_begin 可以指定距离左(或者上)边开始的固定位置
-
layout_constraintGuide_end 可以指定距离右(或者下)边开始的固定位置
-
layout_constraintGuide_percent 可以指定位于布局中所在的百分比,比如距离左边 2% 的位置
-
下面是一个使用垂直 Guideline 的示例, Button 相对于 guideline 布局:
-
layout_constraintBottom_creator
<?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">
<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline4"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
-
通过代码来设置 ConstraintLayout 属性
上面只是 XML 布局文件中使用的属性,只能在 XML 布局文件中使用,但是现在针对 UI 做动画的时候,需要通过代码来动态设置 View 的布局属性。下面就来看看如何通过代码来设置这些属性。
ConstraintSet
ConstraintSet 是用来通过代码管理布局属性的集合对象,可以通过这个类来创建各种布局约束,然后把创建好的布局约束应用到一个 ConstraintLayout 上,可以通过如下几种方式来创建 ConstraintSet:
-
手工创建:
c = new ConstraintSet(); c.connect(….); -
从 R.layout.* 对象获取
c.clone(context, R.layout.layout1); -
从 ConstraintLayout 中获取
c.clone(clayout);然后通过 applyTo 函数来应用到ConstraintLayout 上
package com.kowaii.myconstraintlayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone(this,R.layout.activity_main);
ConstraintLayout layout = findViewById(R.id.main_at);
constraintSet.constrainHeight(R.id.button6,200);
constraintSet.applyTo(layout);
}
}
UI效果