Android开发 - 掌握ConstraintLayout(十一)复杂动画!如此简单!

介绍

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

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

传统动画

以往在咱们建立简单动画时,一般咱们会使用app

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

这三种在咱们制做简单动画时很是简单和方便,特别是当咱们只对某个特定的View制做动画时。可是当咱们须要制做复杂动画时,特别是整个页面多个View同时执行动画时,这几种方式就显得力不从心了,须要大量的工做。框架

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

ConstraintLayout动画

咱们这里经过一个示例来讲明ConstraintLayout动画的建立。布局

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

  • 代码:学习

<?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)。
  • 效果:

-w289

  • 代码:
<?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>

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

答案是经过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);

最终效果:

ezgif-5-34173ef48cf2

只需简单的几行代码,就能够实现复杂的动画了!固然本示例为了说明ConstraintLayout动画的建立方法,布局比较简单。
若是须要复杂布局的动画切换,这种方式的优点就很是明显。若是使用传统建立动画方法,则有可能须要大量的时间和代码来实现。

问题探讨

为何须要建立两个布局文件?

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

实际上可能并无你想象的那么很差,建立两个布局文件的目的只是让动画框架知道不一样的约束而已,而后将不一样的约束应用在过渡动画中,你能够在布局中把与约束无关的属性去掉。
若是你实在不喜欢建立两个布局文件的话,固然也能够在代码中来描述不一样的约束。显然这样会大大增长复杂度和代码量。

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

使用共享元素动画固然也能够实现这样的效果,可是使用共享元素动画你也须要建立两个布局,并且关键的不一样是:
使用ConstraintLayout执行动画时,动画先后的View是同一个View对象。
而使用共享元素动画时动画先后的View是两个不一样的View对象!

系列总结

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

在实际开发的过程当中,使用ConstraintLayout会使开发速度有很多的提高,再结合个人另外一个系列《使用Data Binding》,会大大减小开发Android时的工做量,达到事半功倍的效果,提高生产力!

谢谢你的支持!

若有更多疑问,请参考个人其它Android相关博客:个人博客地址

相关文章
相关标签/搜索