谷歌在2016年的IO大会上推出的一种新的布局方式—-ConstraintLayout,这局是一种约束型的布局方式 。在传统的android开发当中,界面基本都是靠编写XML代码完成的,虽然Android Studio也支持可视化的方式来编写界面,但是操作起来并不方便,我们也一直都不推荐使用可视化的方式来编写Android应用程序的界面。 而ConstraintLayout就是为了解决这一现状而出现的。它和传统编写界面的方式恰恰相反,ConstraintLayout非常适合使用可视化的方式来编写界面,但并不太适合使用XML的方式来进行编写。当然,可视化操作的背后仍然还是使用的XML代码来实现的,只不过这些代码是由Android Studio根据我们的操作自动生成的。
另外,ConstraintLayout还有一个优点,它可以有效地解决布局嵌套过多的问题。我们平时编写界面,复杂的布局总会伴随着多层的嵌套,而嵌套越多,程序的性能也就越差。ConstraintLayout则是使用约束的方式来指定各个控件的位置和关系的,它有点类似于RelativeLayout,但远比RelativeLayout要更强大。
对于复杂的的布局,使用传统布局,我们最多的解决办法是各种嵌套,尽管有include可以使用,但并没有在根源上解决,除非这样的界面,通过自定义View来实现,又有点得不偿失。而ConstraintLayout可以在平面视图层次结构创建大而复杂的布局(无嵌套视图组),减少布局的层级, 优化渲染性能。它类似于RelativeLayout,因为所有视图都是根据兄弟视图和父容器之间的关系来布局的,但它比RelativeLayout更灵活,并且更易于与Android Studio的Layout Editor一起使用。至于,在ConstraintLayout中如何完成界面编写,后续讲解。
在这里又有一个疑问,ConstraintLaytout对于低版本是否兼容呢?ConstraintLaytout本事是由support库来提供的,它可适用于与Android 2.3(API级别9)及更高版本兼容的API库。
1.布局常用的属性介绍。
它的通用形式:
app:layout_constraintAA_toBBOf ="@+id/view"// 将所需A视图的(x方位)与另一个B视图的(x方位)对齐。
layout_constraintTop_toTopOf // 将所需视图的顶部与另一个视图的顶部对齐。
layout_constraintTop_toBottomOf // 将所需视图的顶部与另一个视图的底部对齐。
layout_constraintBottom_toTopOf // 将所需视图的底部与另一个视图的顶部对齐。
layout_constraintBottom_toBottomOf // 将所需视图的底部与另一个视图的底部对齐。
layout_constraintLeft_toTopOf // 将所需视图的左侧与另一个视图的顶部对齐。
layout_constraintLeft_toBottomOf // 将所需视图的左侧与另一个视图的底部对齐。
layout_constraintLeft_toLeftOf // 将所需视图的左边与另一个视图的左边对齐。
layout_constraintLeft_toRightOf // 将所需视图的左边与另一个视图的右边对齐。
layout_constraintRight_toTopOf // 将所需视图的右对齐到另一个视图的顶部。
layout_constraintRight_toBottomOf // 将所需视图的右对齐到另一个的底部。
layout_constraintRight_toLeftOf // 将所需视图的右边与另一个视图的左边对齐。
layout_constraintRight_toRightOf // 将所需视图的右边与另一个视图的右边对齐。
2.LayoutEditor编辑介绍
- Palette 提供Android中常用的控件,我们可以直接拖入右边的可操作界面使用。
- 这里展示的是当前布局的View树,点击当前控件操作界面的。
- 这里都是控制着当前选中控件的margin和当前控件自身的大小。
- 控制着当前控件的其他属性,包括背景,字体大小,消失隐藏等。
- 工具栏,提供在编辑器中配置布局外观和编辑布局属性的按钮。
- blueprint,设计图我们的编辑窗口
- 切换预览和xml文件的按钮
3.工具栏介绍
- 切换设计和实际预览图,Blueprint显示蓝色背景和当前每个控件的轮廓,Design显示实际运行显示的样式。
- 用于旋转屏幕后的预览
- 可以用于显示设备类型,屏幕尺寸密度,还可以选择AndroidTV,和Android Wear等设备
- Android的不同版本
- 切换AppTheme
- 用于选择显示 UI 字符串的语言。此列表仅显示字符串资源中可用的语言。
- 点击1切换成Blueprint视图,可以选择查看控件之间的约束关系,和margin边距
- 设置新拖入的布局是否自动添加约束
- 设置新拖入的布局的默认边距
- 清空控件之间所有约束关系
- 自动推断所有视图的约束
- expand 扩张水平方向,垂直方向剩余的空间
- 设置控件的水平,垂直的对齐方式。
- 添加一条指示线
4.链条(Chains)
ConstraintLayout的链条主要描述的就是将水平方向或者竖直方向上的两个控件或更多控件连在一起,对外有统一的表现方式。具体的表现如下:
由一个控件作为头,身后的控件可以自动居中显示。如果是水平方向左边第一个View就是Header,竖直方向左上方的View为Header。这里我们必须知道layout_constraintHorizontal_chainStyle和layout_constraintVertical_chainStyle,介绍他的三种表现形式:
具体的代码实现:
<?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:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="64dp"
android:text="heads"
app:layout_constraintEnd_toStartOf="@+id/tv2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="64dp"
android:text="TextView"
app:layout_constraintEnd_toStartOf="@+id/tv3"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/tv1"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="8dp"
android:layout_marginTop="64dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/tv2"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textView12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="64dp"
android:text="heads"
app:layout_constraintEnd_toStartOf="@+id/textView13"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv1" />
<TextView
android:id="@+id/textView13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="TextView"
app:layout_constraintEnd_toStartOf="@+id/textView14"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/textView12"
app:layout_constraintTop_toTopOf="@+id/textView12" />
<TextView
android:id="@+id/textView14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="8dp"
android:text="TextView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/textView13"
app:layout_constraintTop_toTopOf="@+id/textView13" />
</android.support.constraint.ConstraintLayout>
1.layout_constraintHorizontal_chainStyle="spread",默认样式三者等分屏幕的宽度。
2.layout_constraintHorizontal_chainStyle="spread_inside" 从上图可以看出头view,与尾view是贴着左右边距的,上图中没有贴着是因为我们给上面两个控件加上了margin16dp。
3第三种属于加权链,和LinearLayout的Weight类似。
链的默认行为是在可用空间中平均分配元素。 如果一个或多个元素使用match_constraint
,它们将使用剩余的空白空间(在它们之间相等)。 属性layout_constraintHorizontal_weight和layout_constraintVertical_weight将决定这些都设置了match_constraint
的View如何分配空间。 例如,在包含使用match_constraint
的两个元素的链上,第一个元素使用权重为2,第二个元素的权重为1,第一个元素占用的空间将是第二个元素的两倍
下面是上面图片的具体实现:
<?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:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="64dp"
android:text="heads"
app:layout_constraintEnd_toStartOf="@+id/button2"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView12" />
<Button
android:id="@+id/button2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintStart_toEndOf="@+id/button"
app:layout_constraintTop_toTopOf="@+id/button" />
<Button
android:id="@+id/button4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="64dp"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button5"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_weight="3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />
<Button
android:id="@+id/button5"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/button6"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintStart_toEndOf="@+id/button4"
app:layout_constraintTop_toTopOf="@+id/button4" />
<Button
android:id="@+id/button6"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="8dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="@+id/button5"
app:layout_constraintTop_toTopOf="@+id/button5" />
</android.support.constraint.ConstraintLayout>
1.约束性布局根据原型图设计布局思路
2.那些布局最适合用
3.约束性的坑
4.其他(动画)
FrameMetrics
从 7.0(API 24)开始,安卓 SDK 新增 OnFrameMetricsAvailableListener 接口用于提供帧绘制各阶段的耗时,数据源与 GPU Profile 相同。
回调接口为 Window.FrameMetrics:
public interface OnFrameMetricsAvailableListener {
void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics, int dropCountSinceLastInvocation);
}
FrameMetrics存储了如下的数据
阶段 | 含义(纳秒) | 备注 |
ANIMATION_DURATION | 动画耗时 | |
DRAW_DURATION | 创建和更新DisplayList耗时 | |
FIRST_DRAW_FRAME | 布尔值,标志该帧是否为此 Window 绘制的第一帧 | |
INPUT_HANDLING_DURATION | 处理用户输入操作的耗时 | |
INTENDED_VSYNC_TIMESTAMP | 预期VSync到来的时间戳 | |
LAYOUT_MEASURE_DURATION | layout/measure耗时 | |
SWAP_BUFFERS_DURATION | GPU在等待GPU完成渲染的耗时 | |
SYNC_DURATION | 上传bitmap到GPU耗时 | |
TOTAL_DURATION | 整帧渲染耗时 | |
UNKNOWN_DELAY_DRRATION | 位置延迟 | |
VSYNC_TIMESTAMP | VSync时机到来的时间戳 |