[AS3.0.1]Android 5.0新特性跳转动画Transition

前言

很早的时候算是看过一些关于Android 5.0的新特性,但是当时也就是记录一下用法,也没后续去看,前段时间看到一个动画切换效果,我还傻乎乎的去写,后来发现居然是Android自带的,找了些资料算是补习了!
本篇包括TransitionShared ElementCircular Reveal的内容。


Transition

Transition是Android 5.0新加入的过渡动画效果,包括ExplodeSlideFade

ExplodeSlideFade
从中心移入或移出从边缘移入或移出调整透明度产生渐变
Explode SlideFade

在讲解这些功能之前我们需要知道几个方法

  • setEnterTransition(Transition transition)
    设置当前页面进入的过渡动画
  • setReturnTransition(Transition transition)
    设置当前页面返回的过渡动画
  • setExitTransition(Transition transition)
    设置当前页面退出的过渡动画
  • setReenterTransition(Transition transition)
    设置当前页面重启的过渡动画

这几个方法是设置过渡动画的时候需要注意的。

Explode

我们这边需要做一个A -> B 然后B进行Explode过渡动画的效果设置。
逻辑如下:
A页面进入B页面 B页面需要有过渡动画 所以只要对B页面设置setEnterTransition方法和setReturnTransition方法即
可。

调用方法也要传入对应的代码才有效

Intent intent = new Intent(activity, TransitionActivity.class);
intent.putExtra("transition", "Explode");
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());

当直接使用ActivityOptions.makeSceneTransitionAnimation(activity)的时候在低于5.0以下的时候软件会直接崩溃,所以可以使用ActivityOptionsCompat来兼容低版本,但是这样设置只是让低版本不会崩溃,并不会有过渡动画效果,后面我会用ActivityOptionsCompat做演示。

在接受到的页面加入以下判断


        transition = getIntent().getStringExtra("transition");

        if (transition != null) {
            switch (transition) {
                case "Explode":
                    Explode explode = new Explode();
                    setDuration(explode);
                    getWindow().setEnterTransition(explode);
                    break;
            }
        }

至此就实现了功能,不设置setReturnTransition系统会自动调用进入的反向动画来实现!

Slide

和上面的Explode一样我们只要加入以下代码

 Intent intent = new Intent(activity, TransitionActivity.class);
 intent.putExtra("transition", "Slide");
 startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());

在需要展示的页面加入判断,不过由于Slide是需要设置到底从哪个方向的所以可以加入方向

        transition = getIntent().getStringExtra("transition");

        if (transition != null) {
            switch (transition) {
            ...
                case "Slide":
                    Slide slide = new Slide();
                    slide.setSlideEdge(Gravity.RIGHT);
                    setDuration(slide);
                    getWindow().setEnterTransition(slide);
                    break;
            }
        }

Fade

这个过渡也没有特别的直接调用以下代码就可以了

 Intent intent = new Intent(activity, TransitionActivity.class);
 intent.putExtra("transition", "Fade");
 startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());

设置展示

        transition = getIntent().getStringExtra("transition");

        if (transition != null) {
            switch (transition) {
            ...
                case "Fade":
                    Fade fade = new Fade();
                    setDuration(fade);
                    getWindow().setEnterTransition(fade);
                    break;
            }
        }

补充setReturnTransition

至此可以发现使用特别简单。下面我们设置setReturnTransition方法来实现进入和退出不一样的效果
在这里插入图片描述

可以看到进入是一个有回弹效果的,并且退出的方向也和进入的相同了!

打开页面的代码也没有特别的变化

Intent intent = new Intent(activity, TransitionActivity.class);
intent.putExtra("transition", "Slide2");
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());

展示的代码

        transition = getIntent().getStringExtra("transition");

        if (transition != null) {
            switch (transition) {
            ...
                case "Slide2":
                    Slide slide2 = new Slide();
                    slide2.setSlideEdge(Gravity.RIGHT);
                    setDuration(slide2);
                    //回弹效果
                    slide2.setInterpolator(new BounceInterpolator());
                    getWindow().setEnterTransition(slide2);
                    break;
            }
        }

前面的代码都没有特别的变化!


只是在最后返回的时候对setReturnTransition进行了修改。

    @Override
    public void onBackPressed() {
        if (transition != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            // 如果没有 return transition 被定义,将使用反进入的动画
            switch (transition) {
                case "Slide2":
                    Slide slide = new Slide();
                    slide.setSlideEdge(Gravity.LEFT);
                    setDuration(slide);
                    getWindow().setReturnTransition(slide);
                    break;
            }
            //一定要调用finishAfterTransition
            finishAfterTransition();
        } else {
            super.onBackPressed();
        }
    }

这边需要注意的就是调用的关闭页面方法一定要是finishAfterTransition才会执行过渡动画。


Shared Element

上面讲完了Transition现在来说下Shared Element就是共享元素。
首先我们看下效果
Shared Element

这就是元素共享的界面过渡动画效果,下面我们看下如何实现!

单独元素并且不传递图片

这次我们使用ActivityCompatActivityOptionsCompat来实现 这是为了兼容低版本,让低版本不崩溃而已!效果是没办法实现!

首先布局页面代码为

    <TextView
        android:id="@+id/tv_1_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="24dp"
        android:layout_marginTop="24dp"
        android:background="@android:color/holo_blue_bright"
        android:gravity="center"
        android:text="点击单独放大"
        android:transitionName="Open"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

我们发现布局上面加入了一段android:transitionName="Open"这是为了让元素进行共享的起点。


打开页面的代码如下

tv1 = findViewById(R.id.tv_1_ase);

Intent intent = new Intent(activity, SharedActivity.class);
ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, tv1,
        ViewCompat.getTransitionName(tv1));
ActivityCompat.startActivity(activity, intent, compat.toBundle());

我们对比上面的代码会发现也是调用makeSceneTransitionAnimation方法,不过传递的不在是一个Explode这类对象了,而是传递了一个view 并且还传递了TransitionName,这个可以直接写或者取!


之后是我们需要展示效果的页面
需要进行过渡动画的View布局代码

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="200dp"
        android:transitionName="Open"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/homepage_banner2" />

这样我们两边就都有了一个android:transitionName="Open"这样进行跳转之后系统就会帮我们绑定两个View

对于展示页面我们可以不需要写任何代码!

多个元素并且不传递图片

多个元素其实也是一样的,只不过传递的view多了而已!

首先还是布局,我们写入了两个transitionName
进入前的布局

    <TextView
        android:id="@+id/tv_1_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="24dp"
        android:layout_marginTop="24dp"
        android:background="@android:color/holo_blue_bright"
        android:gravity="center"
        android:text="点击单独放大"
        android:transitionName="Open"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_2_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="24dp"
        android:background="@android:color/holo_orange_dark"
        android:gravity="center"
        android:text="点击放大2个"
        android:transitionName="Open2"
        app:layout_constraintStart_toEndOf="@+id/tv_1_ase"
        app:layout_constraintTop_toTopOf="@+id/tv_1_ase" />

进入后的布局

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="200dp"
        android:transitionName="Open"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/homepage_banner2" />

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:transitionName="Open2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView"
        app:srcCompat="@mipmap/homepage_banner1" />

这边各自对应了各自的android:transitionName


跳转代码

Pair<View, String> p1 = new Pair<View, String>(tv1, ViewCompat.getTransitionName(tv1));
Pair<View, String> p2 = new Pair<View, String>(tv2, ViewCompat.getTransitionName(tv2));
ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, p1, p2);
Intent intent = new Intent(activity, SharedActivity.class);
ActivityCompat.startActivity(activity, intent, compat.toBundle());

我们创建多个Pair对象在传入就可以了

元素传递图片

上面都是内部本身就有了图片,外部只是一个位置提供而已,那么能够在外部传入图片进去么。是可以的,其实效果只是告诉第二个页面进入之后你的图片需要设置什么而已,实际其实是一样的!

我们新增两个按钮布局

    <TextView
        android:id="@+id/tv_3_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginTop="24dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="自定义图片1"
        android:transitionName="Open3"
        app:layout_constraintStart_toStartOf="@+id/tv_1_ase"
        app:layout_constraintTop_toBottomOf="@+id/tv_1_ase" />

    <TextView
        android:id="@+id/tv_4_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginTop="24dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="自定义图片2"
        android:transitionName="Open3"
        app:layout_constraintEnd_toEndOf="@+id/tv_2_ase"
        app:layout_constraintTop_toBottomOf="@+id/tv_2_ase" />

并且在跳转页面也加入一个布局用于展示

    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="180dp"
        android:layout_height="180dp"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:transitionName="Open3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

这是一个没有设置图片的View,当进入之后才设置图片

跳转代码如下

tv3.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                new Pair<View, String>(tv3, ViewCompat.getTransitionName(tv3))
        );
        Intent intent = new Intent(activity, SharedActivity.class);
        intent.putExtra("imgid", R.mipmap.ic_launcher_round);
        ActivityCompat.startActivity(activity, intent, compat.toBundle());
    }
});

tv4.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                new Pair<View, String>(tv4, ViewCompat.getTransitionName(tv4))
        );
        Intent intent = new Intent(activity, SharedActivity.class);
        intent.putExtra("imgid", R.mipmap.ic_launcher);
        ActivityCompat.startActivity(activity, intent, compat.toBundle());
    }
});

这次我们就需要设置图片了,所以展示页面代码如下

        img3 = findViewById(R.id.imageView3);
        imgId = getIntent().getIntExtra("imgid", -1);
        if (imgId != -1) {
            Glide.with(this).load(imgId).into(img3);
        }

这样设置之后我们进入之后就是传递的图片了!

注:当然也可以是网络图片,不过由于网络的原因,所以建议是直接先传在跳转前的图片,进入之后等网络自己刷新新的图片就好了!

补充1 监听两个跳转页面直接的关联

有可能会做一个轮播的点击跳转的,然后内部切换之后返回回来就会发现位置明显不对或者外部的轮播图片并未改变,这个时候我们只要加入监听就好了!

逻辑如下:
A 在a图片的时候 进入 B 并且打开了a图片,这个时候B 切换了下图片变成了b图片,这个时候返回需要告诉A图片换了。


首先在A的onCreate中加入监听

setExitSharedElementCallback(new SharedElementCallback() {
    @Override
    public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
        if (bundle != null) {
            int id = bundle.getInt("imgId");
            String url = bundle.getString("imgUrl");
            Log.e("-s-", "id = " + id);
            Log.e("-s-", "url = " + url);
            bundle = null;
        }
    }
});

然后实现Activity的onActivityReenter方法,即页面跳转回来之后判断传回来的data

    @Override
    public void onActivityReenter(int resultCode, Intent data) {
        Log.e("-s-", "resultCode = " + resultCode);
        if (resultCode == 101) {
            bundle = new Bundle(data.getExtras());
        }
    }

至此A页面的监听写完了,再来看下B页面的传递信息
将传递信息的代码写在finishAfterTransition方法中

    @Override
    public void finishAfterTransition() {
        Intent data = new Intent();
        data.putExtra("imgId", imgId);
        data.putExtra("imgUrl", imgUrl);
        setResult(101, data);
        super.finishAfterTransition();
    }

这样就实现了两个Activity之间的传递信息功能!

补充2 将TransitionShared Element结合下

实现多种结合的过渡动画,效果如下
Transition+Shared Element

跳转代码

        tv9.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(activity, SharedActivity.class);
                intent.putExtra("transition", "Slide+");
                intent.putExtra("imgurl", imgs[0]);
                ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                        new Pair<View, String>(tv9, ViewCompat.getTransitionName(tv9))
                );
                ActivityCompat.startActivity(activity, intent, compat.toBundle());
            }
        });

和上面比就是加入了一些参数而已。
实现页面代码

        img3 = findViewById(R.id.imageView3);

        imgId = getIntent().getIntExtra("imgid", -1);
        imgUrl = getIntent().getStringExtra("imgurl");

        transition = getIntent().getStringExtra("transition");
        if (transition != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            switch (transition) {
                case "Slide+":
                    Slide slide = new Slide();
                    slide.setSlideEdge(Gravity.RIGHT);
                    getWindow().setEnterTransition(slide);
                    break;
            }
        }
        if (imgUrl != null) {
            Glide.with(this).load(imgUrl).into(img3);
        } else if (imgId != -1) {
            Glide.with(this).load(imgId).into(img3);
        }

就是将Transition和SharedElement简单结合而已。


Circular Reveal

这个效果是在当前页面进行一个扩散过渡。但是可以做到加入到跳转动画中!
效果如下
Circular Reveal

基本说明

先说下最基本的使用说明
其实就是调用ViewAnimationUtils.createCircularReveal创建一个Animator,说白了就是一个Animator,只不过官方提供了一个扩散效果动画给你而已_(:з」∠)_
createCircularReveal提供了5个参数View view, int centerX, int centerY, float startRadius, float endRadius,分别代表,需要执行的动画是哪个View,起始位置的X,Y, 开始圆的半径, 结束圆的半径!

这边扩散整个布局的代码

    private void show(View v) {
        int w = getResources().getDisplayMetrics().widthPixels;
        int h = getResources().getDisplayMetrics().heightPixels;
        int cx = (v.getLeft() + v.getRight()) / 2;
        int cy = (v.getTop() + v.getBottom()) / 2;
        float r = Math.max(w, h);
        Animator animator = ViewAnimationUtils.createCircularReveal(root, cx, cy, 0, r);
        animator.setDuration(500).setInterpolator(new AccelerateDecelerateInterpolator());
        animator.start();
    }

效果的逻辑很简单

A 以SharedElement打开 B ,之后立马执行CircularReveal扩散整个根布局, 退出B的时候必须先执行完CircularReveal动画在关闭页面。

代码如下
跳转代码

        tv10.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(activity, CircularRevealActivity.class);
                intent.putExtra("CircularReveal", "green");
                ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                        new Pair<View, String>(tv10, ViewCompat.getTransitionName(tv10))
                );
                ActivityCompat.startActivity(activity, intent, compat.toBundle());
            }
        });

执行效果页面代码

CircularRevealActivity.java
package com.gjn.testproject;

import android.animation.Animator;
import android.app.SharedElementCallback;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.animation.AccelerateDecelerateInterpolator;

import java.util.List;

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class CircularRevealActivity extends AppCompatActivity {

    View root;
    View v1, v2, v3;
    boolean in = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_circular_reveal);
        in = false;
        root = findViewById(R.id.root_acr);
        v1 = findViewById(R.id.v1);
        v2 = findViewById(R.id.v2);
        v3 = findViewById(R.id.v3);

        String circularReveal = getIntent().getStringExtra("CircularReveal");

        if (circularReveal != null) {
            switch (circularReveal) {
                case "green":
                    root.setBackgroundResource(android.R.color.holo_green_light);
                    break;
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                setEnterSharedElementCallback(new SharedElementCallback() {
                    @Override
                    public void onSharedElementEnd(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
                        if (!in) {
                            in = true;
                            show(v1);
                        }
                    }
                });
            }
        }

        v1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                root.setBackgroundResource(android.R.color.holo_green_light);
                show(v1);
            }
        });

        v2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                root.setBackgroundResource(android.R.color.holo_red_dark);
                show(v2);
            }
        });

        v3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                root.setBackgroundResource(android.R.color.holo_blue_light);
                show(v3);
            }
        });

    }

    @Override
    public void onBackPressed() {
        if (in && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            hide(v1);
        } else {
            super.onBackPressed();
        }
    }

    private void show(View v) {
        int w = getResources().getDisplayMetrics().widthPixels;
        int h = getResources().getDisplayMetrics().heightPixels;
        int cx = (v.getLeft() + v.getRight()) / 2;
        int cy = (v.getTop() + v.getBottom()) / 2;
        float r = Math.max(w, h);
        Animator animator = ViewAnimationUtils.createCircularReveal(root, cx, cy, 0, r);
        animator.setDuration(500).setInterpolator(new AccelerateDecelerateInterpolator());
        animator.start();
    }

    private void hide(View v) {
        int w = getResources().getDisplayMetrics().widthPixels;
        int h = getResources().getDisplayMetrics().heightPixels;
        int cx = (v.getLeft() + v.getRight()) / 2;
        int cy = (v.getTop() + v.getBottom()) / 2;
        float r = Math.max(w, h);
        Animator animator = ViewAnimationUtils.createCircularReveal(root, cx, cy, r, 0);
        animator.setDuration(500).setInterpolator(new AccelerateDecelerateInterpolator());
        animator.start();

        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                root.setBackgroundColor(Color.TRANSPARENT);
                finishAfterTransition();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

    }
}

具体就看代码吧!其实就是做了两个动画而已!


全部代码

activity_shared_element.xml

<?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"
    tools:context="com.gjn.testproject.SharedElementActivity">

    <TextView
        android:id="@+id/tv_1_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="24dp"
        android:layout_marginTop="24dp"
        android:background="@android:color/holo_blue_bright"
        android:gravity="center"
        android:text="点击单独放大"
        android:transitionName="Open"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_2_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="24dp"
        android:background="@android:color/holo_orange_dark"
        android:gravity="center"
        android:text="点击放大2个"
        android:transitionName="Open2"
        app:layout_constraintStart_toEndOf="@+id/tv_1_ase"
        app:layout_constraintTop_toTopOf="@+id/tv_1_ase" />

    <TextView
        android:id="@+id/tv_3_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginTop="24dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="自定义图片1"
        android:transitionName="Open3"
        app:layout_constraintStart_toStartOf="@+id/tv_1_ase"
        app:layout_constraintTop_toBottomOf="@+id/tv_1_ase" />

    <TextView
        android:id="@+id/tv_4_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginTop="24dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="自定义图片2"
        android:transitionName="Open3"
        app:layout_constraintEnd_toEndOf="@+id/tv_2_ase"
        app:layout_constraintTop_toBottomOf="@+id/tv_2_ase" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_ase"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_3_ase" />

    <TextView
        android:id="@+id/tv_5_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="24dp"
        android:gravity="center"
        android:text="Explode"
        app:layout_constraintStart_toEndOf="@+id/tv_2_ase"
        app:layout_constraintTop_toTopOf="@+id/tv_2_ase" />

    <TextView
        android:id="@+id/tv_6_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginStart="24dp"
        android:gravity="center"
        android:text="Slide1"
        app:layout_constraintStart_toEndOf="@+id/tv_5_ase"
        app:layout_constraintTop_toTopOf="@+id/tv_5_ase" />

    <TextView
        android:id="@+id/tv_7_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="Fade"
        app:layout_constraintStart_toStartOf="@+id/tv_5_ase"
        app:layout_constraintTop_toTopOf="@+id/tv_4_ase" />

    <TextView
        android:id="@+id/tv_8_ase"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginTop="24dp"
        android:gravity="center"
        android:text="Slide2"
        app:layout_constraintStart_toStartOf="@+id/tv_6_ase"
        app:layout_constraintTop_toBottomOf="@+id/tv_6_ase" />

    <TextView
        android:id="@+id/tv_9_ase"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="16dp"
        android:background="@android:color/holo_green_light"
        android:gravity="center"
        android:transitionName="Open3"
        android:text="Slide+SharedElements"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/rv_ase" />

    <TextView
        android:id="@+id/tv_10_ase"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:background="@android:color/holo_green_light"
        android:gravity="center"
        android:text="CircularReveal1"
        android:transitionName="Open4"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_9_ase" />

</android.support.constraint.ConstraintLayout>

activity_shared.xml

<?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"
    tools:context="com.gjn.testproject.SharedActivity">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="200dp"
        android:transitionName="Open"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:srcCompat="@mipmap/homepage_banner2" />

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:transitionName="Open2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView"
        app:srcCompat="@mipmap/homepage_banner1" />

    <ImageView
        android:id="@+id/imageView3"
        android:layout_width="180dp"
        android:layout_height="180dp"
        android:layout_marginBottom="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:transitionName="Open3"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent" />

</android.support.constraint.ConstraintLayout>

activity_circular_reveal.xml

<?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:id="@+id/root_acr"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.gjn.testproject.CircularRevealActivity">

    <TextView
        android:id="@+id/v1"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="150dp"
        android:transitionName="Open4"
        android:background="@android:color/holo_green_light"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/v2"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginBottom="32dp"
        android:layout_marginEnd="32dp"
        android:background="@android:color/holo_red_dark"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <TextView
        android:id="@+id/v3"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginEnd="24dp"
        android:background="@android:color/holo_blue_light"
        app:layout_constraintBottom_toBottomOf="@+id/v2"
        app:layout_constraintEnd_toStartOf="@+id/v2" />


</android.support.constraint.ConstraintLayout>
SharedElementActivity.java
package com.gjn.testproject;

import android.app.Activity;
import android.app.ActivityOptions;
import android.app.SharedElementCallback;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.util.Pair;
import android.support.v4.view.ViewCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.gjn.baserecycleradapterlibrary.BaseRecyclerAdapter;
import com.gjn.baserecycleradapterlibrary.RecyclerViewHolder;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class SharedElementActivity extends AppCompatActivity {

    TextView tv1, tv2, tv3, tv4, tv5, tv6, tv7, tv8, tv9, tv10;

    Activity activity;

    String[] imgs = {"https://ws1.sinaimg.cn/large/0065oQSqgy1fxd7vcz86nj30qo0ybqc1.jpg",
            "https://ws1.sinaimg.cn/large/0065oQSqgy1fwyf0wr8hhj30ie0nhq6p.jpg",
            "https://ws1.sinaimg.cn/large/0065oQSqgy1fwgzx8n1syj30sg15h7ew.jpg",
            "https://ws1.sinaimg.cn/large/0065oQSqly1fw8wzdua6rj30sg0yc7gp.jpg",
            "https://ws1.sinaimg.cn/large/0065oQSqly1fuh5fsvlqcj30sg10onjk.jpg",
            "https://ws1.sinaimg.cn/large/0065oQSqly1fubd0blrbuj30ia0qp0yi.jpg"};
    Bundle bundle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        //设置允许通过ActivityOptions.makeSceneTransitionAnimation发送或者接收Bundle
//        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
//        //设置使用TransistionManager进行动画,不设置的话系统会使用一个默认的TransitionManager
//        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        setContentView(R.layout.activity_shared_element);

        activity = this;

        tv1 = findViewById(R.id.tv_1_ase);
        tv2 = findViewById(R.id.tv_2_ase);
        tv3 = findViewById(R.id.tv_3_ase);
        tv4 = findViewById(R.id.tv_4_ase);
        tv5 = findViewById(R.id.tv_5_ase);
        tv6 = findViewById(R.id.tv_6_ase);
        tv7 = findViewById(R.id.tv_7_ase);
        tv8 = findViewById(R.id.tv_8_ase);
        tv9 = findViewById(R.id.tv_9_ase);
        tv10 = findViewById(R.id.tv_10_ase);
        RecyclerView RV = findViewById(R.id.rv_ase);

        List<String> list = new ArrayList<>();

        list.add("图片1");
        list.add("图片2");
        list.add("图片3");
        list.add("图片4");
        list.add("图片5");
        list.add("图片6");

        RV.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
        BaseRecyclerAdapter<String> adapter = new BaseRecyclerAdapter<String>(activity, R.layout.item_ase, list) {
            @Override
            public void bindData(RecyclerViewHolder holder, String s, int i) {
                holder.setTextViewText(R.id.tv_ia, s);
            }
        };
        RV.setAdapter(adapter);

        adapter.setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int i) {
                TextView textView = view.findViewById(R.id.tv_ia);
                ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                        new Pair<View, String>(textView, ViewCompat.getTransitionName(textView))
                );
                Intent intent = new Intent(activity, SharedActivity.class);
                intent.putExtra("imgurl", imgs[i]);
                ActivityCompat.startActivity(activity, intent, compat.toBundle());
            }
        });


        setClick();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            setExitSharedElementCallback(new SharedElementCallback() {
                @Override
                public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
                    if (bundle != null) {
                        int id = bundle.getInt("imgId");
                        String url = bundle.getString("imgUrl");
                        Log.e("-s-", "id = " + id);
                        Log.e("-s-", "url = " + url);
                        bundle = null;
                    }
                }
            });
        }
    }

    @Override
    public void onActivityReenter(int resultCode, Intent data) {
        Log.e("-s-", "resultCode = " + resultCode);
        if (resultCode == 101) {
            bundle = new Bundle(data.getExtras());
        }
    }

    private void setClick() {

        tv1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(activity, SharedActivity.class);
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity, tv1,
                        ViewCompat.getTransitionName(tv1)).toBundle());
            }
        });

        tv2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Pair<View, String> p1 = new Pair<View, String>(tv1, ViewCompat.getTransitionName(tv1));
                Pair<View, String> p2 = new Pair<View, String>(tv2, ViewCompat.getTransitionName(tv2));
                ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, p1, p2);
                Intent intent = new Intent(activity, SharedActivity.class);
                ActivityCompat.startActivity(activity, intent, compat.toBundle());
            }
        });

        tv3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                        new Pair<View, String>(tv3, ViewCompat.getTransitionName(tv3))
                );
                Intent intent = new Intent(activity, SharedActivity.class);
                intent.putExtra("imgid", R.mipmap.ic_launcher_round);
                ActivityCompat.startActivity(activity, intent, compat.toBundle());
            }
        });

        tv4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                        new Pair<View, String>(tv4, ViewCompat.getTransitionName(tv4))
                );
                Intent intent = new Intent(activity, SharedActivity.class);
                intent.putExtra("imgid", R.mipmap.ic_launcher);
                ActivityCompat.startActivity(activity, intent, compat.toBundle());
            }
        });

        tv5.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(activity, TransitionActivity.class);
                intent.putExtra("transition", "Explode");
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());
            }
        });

        tv6.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(activity, TransitionActivity.class);
                intent.putExtra("transition", "Slide");
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());
            }
        });

        tv7.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(activity, TransitionActivity.class);
                intent.putExtra("transition", "Fade");
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());
            }
        });

        tv8.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(activity, TransitionActivity.class);
                intent.putExtra("transition", "Slide2");
                startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(activity).toBundle());
            }
        });

        tv9.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(activity, SharedActivity.class);
                intent.putExtra("transition", "Slide+");
                intent.putExtra("imgurl", imgs[0]);
                ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                        new Pair<View, String>(tv9, ViewCompat.getTransitionName(tv9))
                );
                ActivityCompat.startActivity(activity, intent, compat.toBundle());
            }
        });

        tv10.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(activity, CircularRevealActivity.class);
                intent.putExtra("CircularReveal", "green");
                ActivityOptionsCompat compat = ActivityOptionsCompat.makeSceneTransitionAnimation(activity,
                        new Pair<View, String>(tv10, ViewCompat.getTransitionName(tv10))
                );
                ActivityCompat.startActivity(activity, intent, compat.toBundle());
            }
        });

    }
}
TransitionActivity.java
package com.gjn.testproject;

import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.transition.Explode;
import android.transition.Fade;
import android.transition.Slide;
import android.transition.Transition;
import android.view.Gravity;
import android.view.animation.BounceInterpolator;

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class TransitionActivity extends AppCompatActivity {

    private String transition;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_transition);

        transition = getIntent().getStringExtra("transition");

        if (transition != null) {
            switch (transition) {
                case "Explode":
                    Explode explode = new Explode();
                    setDuration(explode);
                    getWindow().setEnterTransition(explode);
                    break;
                case "Slide":
                    Slide slide = new Slide();
                    slide.setSlideEdge(Gravity.RIGHT);
                    setDuration(slide);
                    getWindow().setEnterTransition(slide);
                    break;
                case "Slide2":
                    Slide slide2 = new Slide();
                    slide2.setSlideEdge(Gravity.RIGHT);
                    setDuration(slide2);
                    //回弹效果
                    slide2.setInterpolator(new BounceInterpolator());
                    getWindow().setEnterTransition(slide2);
                    break;
                case "Fade":
                    Fade fade = new Fade();
                    setDuration(fade);
                    getWindow().setEnterTransition(fade);
                    break;
            }
        }
    }

    private void setDuration(Transition transition) {
        transition.setDuration(800);
    }

    @Override
    public void onBackPressed() {
        if (transition != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            // 如果没有 return transition 被定义,将使用反进入的动画
            switch (transition) {
//                case "Explode":
//                    Explode explode = new Explode();
//                    getWindow().setReturnTransition(explode);
//                    break;
//                case "Slide":
//                    Slide slide = new Slide();
//                    slide.setSlideEdge(Gravity.RIGHT);
//                    getWindow().setReturnTransition(slide);
//                    break;
                case "Slide2":
//                    Slide slide2 = new Slide();
//                    slide2.setSlideEdge(Gravity.RIGHT);
//                    //回弹效果
//                    slide2.setInterpolator(new BounceInterpolator());
//                    getWindow().setReturnTransition(slide2);
                    Slide slide = new Slide();
                    slide.setSlideEdge(Gravity.LEFT);
                    setDuration(slide);
                    getWindow().setReturnTransition(slide);
                    break;
//                case "Fade":
//                    Fade fade = new Fade();
//                    getWindow().setReturnTransition(fade);
//                    break;
            }
            //一定要调用finishAfterTransition
            finishAfterTransition();
        } else {
            super.onBackPressed();
        }
    }
}

SharedActivity.java
package com.gjn.testproject;

import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.transition.Slide;
import android.view.Gravity;
import android.widget.ImageView;

import com.bumptech.glide.Glide;

public class SharedActivity extends AppCompatActivity {

    int imgId;
    String imgUrl;
    String transition;
    ImageView img3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shared);

        img3 = findViewById(R.id.imageView3);

        imgId = getIntent().getIntExtra("imgid", -1);
        imgUrl = getIntent().getStringExtra("imgurl");

        transition = getIntent().getStringExtra("transition");
        if (transition != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            switch (transition) {
                case "Slide+":
                    Slide slide = new Slide();
                    slide.setSlideEdge(Gravity.RIGHT);
                    getWindow().setEnterTransition(slide);
                    break;
            }
        }
        if (imgUrl != null) {
            Glide.with(this).load(imgUrl).into(img3);
        } else if (imgId != -1) {
            Glide.with(this).load(imgId).into(img3);
        }

    }

    @Override
    public void finishAfterTransition() {
        Intent data = new Intent();
        data.putExtra("imgId", imgId);
        data.putExtra("imgUrl", imgUrl);
        setResult(101, data);
        super.finishAfterTransition();
    }
}
CircularRevealActivity.java
package com.gjn.testproject;

import android.animation.Animator;
import android.app.SharedElementCallback;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.animation.AccelerateDecelerateInterpolator;

import java.util.List;

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class CircularRevealActivity extends AppCompatActivity {

    View root;
    View v1, v2, v3;
    boolean in = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_circular_reveal);
        in = false;
        root = findViewById(R.id.root_acr);
        v1 = findViewById(R.id.v1);
        v2 = findViewById(R.id.v2);
        v3 = findViewById(R.id.v3);

        String circularReveal = getIntent().getStringExtra("CircularReveal");

        if (circularReveal != null) {
            switch (circularReveal) {
                case "green":
                    root.setBackgroundResource(android.R.color.holo_green_light);
                    break;
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                setEnterSharedElementCallback(new SharedElementCallback() {
                    @Override
                    public void onSharedElementEnd(List<String> sharedElementNames, List<View> sharedElements, List<View> sharedElementSnapshots) {
                        if (!in) {
                            in = true;
                            show(v1);
                        }
                    }
                });
            }
        }

        v1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                root.setBackgroundResource(android.R.color.holo_green_light);
                show(v1);
            }
        });

        v2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                root.setBackgroundResource(android.R.color.holo_red_dark);
                show(v2);
            }
        });

        v3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                root.setBackgroundResource(android.R.color.holo_blue_light);
                show(v3);
            }
        });

    }

    @Override
    public void onBackPressed() {
        if (in && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            hide(v1);
        } else {
            super.onBackPressed();
        }
    }

    private void show(View v) {
        int w = getResources().getDisplayMetrics().widthPixels;
        int h = getResources().getDisplayMetrics().heightPixels;
        int cx = (v.getLeft() + v.getRight()) / 2;
        int cy = (v.getTop() + v.getBottom()) / 2;
        float r = Math.max(w, h);
        Animator animator = ViewAnimationUtils.createCircularReveal(root, cx, cy, 0, r);
        animator.setDuration(500).setInterpolator(new AccelerateDecelerateInterpolator());
        animator.start();
    }

    private void hide(View v) {
        int w = getResources().getDisplayMetrics().widthPixels;
        int h = getResources().getDisplayMetrics().heightPixels;
        int cx = (v.getLeft() + v.getRight()) / 2;
        int cy = (v.getTop() + v.getBottom()) / 2;
        float r = Math.max(w, h);
        Animator animator = ViewAnimationUtils.createCircularReveal(root, cx, cy, r, 0);
        animator.setDuration(500).setInterpolator(new AccelerateDecelerateInterpolator());
        animator.start();

        animator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                root.setBackgroundColor(Color.TRANSPARENT);
                finishAfterTransition();
            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });

    }
}

资料

【Transition】Android炫酷的Activity切换效果,共享元素
Activity间的跳转动画—Transition
使用Circular Reveal为你的应用添加揭露动画效果

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值