介绍

本系列我们已经介绍了ConstraintLayout的基本用法。学习到这里,相信你已经熟悉ConstraintLayout的基本使用了,如果你对它的用法还不了解,建议您先阅读我之前的文章

使用ConstraintLayout创建动画的基本思想是我们创建两个不同的布局,每个布局有其不同的约束,从而我们使用其动画框架来进行两种约束之间的切换。

传统动画

以往在我们创建简单动画时,通常我们会使用

  • 视图动画(View Animation)
  • 帧动画(Drawable Animation)
  • 属性动画(Property Animation)

这三种在我们制作简单动画时非常简单和方便,特别是当我们只对某个特定的View制作动画时。但是当我们需要制作复杂动画时,特别是整个页面多个View同时执行动画时,这几种方式就显得力不从心了,需要大量的工作。

当然还有一种方式就是使用转场动画框架(Transition Framework),通过共享元素(Shared Element)制作动画,这个后面我们也会提到。

ConstraintLayout动画

我们这里通过一个示例来说明ConstraintLayout动画的创建。

  1. 首先,我们创建第一个布局(activity_main.xml),它是是我们的初始布局。
  • 效果:

  • 代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
android:id="@+id/cl_root"
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"
tools:context=".MainActivity"> <TextView
android:id="@+id/tv_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="评分:8.3分"
app:layout_constraintStart_toStartOf="@+id/tv_name"
app:layout_constraintTop_toBottomOf="@+id/tv_name" /> <TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="8dp"
android:text="无敌破坏王2"
android:textColor="#282828"
android:textSize="20sp"
app:layout_constraintStart_toEndOf="@+id/iv_poster"
app:layout_constraintTop_toTopOf="@+id/iv_poster" /> <ImageView
android:id="@+id/iv_poster"
android:layout_width="120dp"
android:layout_height="160dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:scaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/wreck_it_ralph" /> </android.support.constraint.ConstraintLayout>

我们的初始布局创建完毕后,我们需要创建一个动画结束布局,让动画框架知道执行完动画后布局是什么样的。

  1. 创建动画结束布局(activity_main_detail.xml)。
  • 效果:

  • 代码:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
android:id="@+id/cl_root"
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"
tools:context=".MainActivity"> <TextView
android:id="@+id/tv_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="52dp"
android:text="评分:8.3分"
app:layout_constraintBottom_toBottomOf="@+id/tv_name"
app:layout_constraintStart_toEndOf="@+id/tv_name"
app:layout_constraintTop_toTopOf="@+id/tv_name"/> <TextView
android:id="@+id/tv_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:text="无敌破坏王2"
android:textColor="#282828"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> <ImageView
android:id="@+id/iv_poster"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="65dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@mipmap/wreck_it_ralph" /> </android.support.constraint.ConstraintLayout>

这个页面是我们执行动画结束后的样子。那么开始和结束的布局我们都有了,我们怎样执行动画,让两个布局之间进行过渡呢?

答案是通过Android的TransitionManager来执行。

  1. 使用TransitionManager来执行动画
  • 代码(MainActivity.java)
package cn.examplecode.constraintlayoutdemo;

import android.support.constraint.ConstraintLayout;
import android.support.constraint.ConstraintSet;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.transition.TransitionManager; public class MainActivity extends AppCompatActivity { private ConstraintLayout mConstraintLayout;
private boolean mIsDetail; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mConstraintLayout = findViewById(R.id.cl_root); ConstraintSet constraintSet1 = new ConstraintSet();
ConstraintSet constraintSet2 = new ConstraintSet(); constraintSet2.clone(this, R.layout.activity_main_detail);
constraintSet1.clone(mConstraintLayout); findViewById(R.id.iv_poster).setOnClickListener(v -> {
TransitionManager.beginDelayedTransition(mConstraintLayout);
if (!mIsDetail) {
constraintSet2.applyTo(mConstraintLayout);
mIsDetail = true;
} else {
constraintSet1.applyTo(mConstraintLayout);
mIsDetail = false;
}
});
}
}

我们来解释以上代码。

首先我们发现使用了这个类ConstraintSet,它是一个约束集合,保存了布局上所有元素的约束,因为我们需要在两个布局之间执行动画,所以我们需要创建两个约束集合的对象。

ConstraintSet constraintSet1 = new ConstraintSet();
ConstraintSet constraintSet2 = new ConstraintSet();

创建完约束集对象后,我们需要设置每个约束集对应的约束:

constraintSet2.clone(this, R.layout.activity_main_detail);
constraintSet1.clone(mConstraintLayout);

这里我们将当前布局的约束应用到constraintSet1中,将目标布局的约束应用到constraintSet2中。

接下来我们执行动画:

TransitionManager.beginDelayedTransition(mConstraintLayout);
# 从constraintSet1过渡到constraintSet2
constraintSet2.applyTo(mConstraintLayout); # 从constraintSet2过渡到constraintSet1
constraintSet1.applyTo(mConstraintLayout);

最终效果:

只需简单的几行代码,就可以实现复杂的动画了!当然本示例为了说明ConstraintLayout动画的创建方法,布局比较简单。

如果需要复杂布局的动画切换,这种方式的优势就非常明显。如果使用传统创建动画方法,则有可能需要大量的时间和代码来实现。

问题探讨

为什么需要创建两个布局文件?

可能有人认为创建两个布局文件不是一个好的方式,两个布局中存在重复的代码,这样好吗?

实际上可能并没有你想象的那么不好,创建两个布局文件的目的只是让动画框架知道不同的约束而已,然后将不同的约束应用在过渡动画中,你可以在布局中把与约束无关的属性去掉。

如果你实在不喜欢创建两个布局文件的话,当然也可以在代码中来描述不同的约束。显然这样会大大增加复杂度和代码量。

与使用共享元素动画(Shared Element)有什么区别?

使用共享元素动画当然也可以实现这样的效果,但是使用共享元素动画你也需要创建两个布局,而且关键的不同是:

使用ConstraintLayout执行动画时,动画前后的View是同一个View对象。

而使用共享元素动画时动画前后的View是两个不同的View对象!

系列总结

本篇是本系列博客《掌握ConstraintLayout》的最后一篇。通过本系列的学习,相信你已经掌握了使用ConstraintLayout的大部分功能。

在实际开发的过程中,使用ConstraintLayout会使开发速度有不少的提升,再结合我的另一个系列《使用Data Binding》,会大大减少开发Android时的工作量,达到事半功倍的效果,提升生产力!

谢谢你的支持!

如有更多疑问,请参考我的其它Android相关博客:我的博客地址

Android开发 - 掌握ConstraintLayout(十一)复杂动画!如此简单!的更多相关文章

  1. Android开发 - 掌握ConstraintLayout(十)按比例设置视图大小

    有时候在布局界面的时候,UI要求某个View或者某张图片按比例显示,以适应不同的屏幕分辨率. 通常我们时通过自定义View或者引入第三方的库来解决.现在我们既然已经使用了ConstraintLayou ...

  2. Android开发 - 掌握ConstraintLayout(一)传统布局的问题

    在传统的Android开发中,页面布局占用了我们很多的开发时间,而且面对复杂页面的时候,传统的一些布局会显得非常复杂,每种布局都有特定的应用场景,我们通常需要各种布局结合起来使用来实现复杂的页面.随着 ...

  3. Android开发 - 掌握ConstraintLayout(九)分组(Group)

    使用ConstraintLayout后我们的布局是没有层级关系的,各个View之间都是平级关系,但是如果根据某个业务条件来控制多个View的显示与否,我们需要分别对每个View进行控制,需要调用多次s ...

  4. Android开发 - 掌握ConstraintLayout(八)障碍线(Barrier)

    本文我们来介绍障碍线(Barrier)的使用,平常在开发中用的相对要少一些,但是在需要时会非常方便. 它的作用是将多个元素放到这个障碍线里面使时,其中的任何元素的大小或位置变化时都会使它的位置进行改变 ...

  5. Android开发 - 掌握ConstraintLayout(七)辅助线(Guideline)

    了解过UI设计的同学都知道,在设计的时候,我们经常在界面上拖进一些辅助线来帮我们对齐UI元素,或者方便我们统一的页边距. 在ConstraintLayout的编辑器中,同样也支持这样的功能,我们可以创 ...

  6. Android开发 - 掌握ConstraintLayout(六)链条(Chains)

    本文我们介绍链条(Chains),使用它可以将多个View连接起来,互相约束. 可以创建横向的链条,也可以创建纵向的链条,我们以横向的链条举例: 我们先创建三个按钮: 我们选中三个按钮后在上面点右键创 ...

  7. Android开发 - 掌握ConstraintLayout(五)偏差(Bias)

    比如实现这样一个场景: "在屏幕宽度的1/4的地方放置一个View" 使用传统布局时,实现按照屏幕的宽度(高度),或者相对两个View之间距离的一个比例来进行布局,就显得非常麻烦, ...

  8. Android开发 - 掌握ConstraintLayout(四)创建基本约束

    上一篇我们介绍了编辑器的基本使用,本文我们介绍创建基本的约束. "约束"表示View之间的位置关系.当我们在ConstraintLayout布局中创建View时,如果我们没有添加任 ...

  9. Android开发 - 掌握ConstraintLayout(三)编辑器

    从本篇博客开始我们开始介绍如何使用ConstraintLayout. 既然ConstraintLayout叫约束布局,首先我们先介绍什么叫约束(Constraints): 约束(Constraints ...

  10. Android开发 - 掌握ConstraintLayout(二)介绍

    介绍 发布时间 ConstraintLayout是在2016的Google I/O大会上发布的,经过这么长时间的更新,现在已经非常稳定. 支持Android 2.3(API 9)+ 目前的Androi ...

随机推荐

  1. MVC开发T4代码生成之二----vs模板扩展

    在上一篇MVC开发T4代码生成之一----文本模板基础中介绍了与T4模板相关的基础知识,并对MVC内使用T4模板添加视图做了介绍.知道了T4模板的使用后自然就想着怎么对vs自带的T4模板进行扩展,添加 ...

  2. C# Task.Run 和 Task.Factory.StartNew 区别

    Task.Run 是在 dotnet framework 4.5 之后才可以使用,但是 Task.Factory.StartNew 可以使用比 Task.Run 更多的参数,可以做到更多的定制.可以认 ...

  3. 主机WiFi时,vmware ubuntu 桥接上网

    1.在vmwared软件主页的编辑->虚拟网络编辑器中,桥接模式,选择桥接至电脑的无线网卡(在主机上查询) 2.虚拟机设置中,选择桥接模式 3.ubuntu 桌面右上方edit connecti ...

  4. linux升级openssh到7.9

    客户linux主机ssh存在高危漏洞,需要进行升级修复. linux联网后,直接命令行: [root@gw ~]# yum update openssl -y 此命令只是小版本的升级,比如将opens ...

  5. Numpy 线性代数

    Numpy 提供了线性代数库 linalg , 该库包含了线性代数所需的所有功能,可以看卡下面的说明: 函数 描述 dot 两个数组的点积, 即元素对应相乘 vdot 两个向量的点积 inner 两个 ...

  6. GUI学习之二——PyQt控件初识

    一.控件概念 控件是一个程序界面上的各个独立的元素, 它具备用户点击.接收用户输入.展示不同内容.存放其他控件等功能. 二.控件分类 常用的控件按功能可以分为以下几种类 按钮 QPushButton— ...

  7. python-directory

    #!/usr/bin/python # --*-- coding: utf-8 --*-- directory={ "张三":16, "李四":46, &quo ...

  8. 笔记javascript

    // var demo1=12;// alert('点击确定按钮看结果'+demo1);// for(var i = 0; i<10;i++)// {//     document.write( ...

  9. Filter的介绍及使用

    转:http://blog.csdn.net/zhaozheng7758/article/details/6105749 一.Filter的介绍及使用 什么是过滤器? 与Servlet相似,过滤器是一 ...

  10. python中os.path 与sys.path

    看别人写的代码,会发现两个和路径设置有关的模块 os 和sys.我对这两个模块也不是特别了解.只是记录一下自己看到的,学到的. python 中我们会使用这两个模块和文件路径, 创建文件 之类的 操作 ...