Android转场动画和共享元素动画兼容5.0以下版本的实现

原创 cheny  2018-04-26 00:51  阅读 1,693 views 次 评论 0 条

版权说明 : 《Android转场动画和共享元素动画兼容5.0以下版本的实现》于当前CSDN博客乘月网属同一原创,转载请说明出处,谢谢。

一款APP让人赏心悦目的APP,动画是它并不可少的部分,Android提供很多原生动画方式如帧动画,属性动画等,也提供了一些组件动画套装,如Activity间的过渡跳转动画,还有Fragment,Dialog等展示动画。本文只讲Android转场动画和共享元素动画。

CySharedElementTransition

A compat library of android shared-element transition for lower api.
一个为Android较低版本api提供Android共享元素转场动画的兼容库。

开源库地址:https://github.com/ausboyue/CySharedElementTransition

Activity转场动画

先看效果图

Activity降落过渡动画 ↓↓↓

anim_up_to_down

Activity左滑过渡动画 ↓↓↓

anim_right_to_left

这些动画一定程度上提高了良好的用户交互视觉感受,但是还有更高层次的过渡动画,那就是基于控件(View)级别的过渡动画(共享元素动画的精髓)。

共享元素动画

Google在Android5.0时开始集成了更多更全面更易于开发者定义的的转场动画和共享元素动画。

下面我们看看示例Google Play:

anim_google_play_example

当你点击app logo时,这个logo会通过动画引导出下一个界面,引导过程中逐渐显示界面剩余的所有元素(View),完成非常平滑界面过渡。由于录制和图片压缩的原因,效果图画面比较模糊,画面有白闪,卡顿现象,真实效果大家可以下载体验下。

然而作为挖坑大师的Google从不吝啬在自己的每一个产品上给开发者挖坑--Android5.0以下版本无法使用该类型的动画

这就意味着如果想让自己的APP气质提高一个档次,在应用这些牛逼的动画时需要这样做?

      if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
            Toast.makeText(context, "请先升级5.0及以上的系统或换好一点的手机吧!", Toast.LENGTH_SHORT).show();
            finish();
            return;
        }

好主意,专治各种不服!可是直到有一天产品小哥突然敲敲地凑到你的耳边对你说:↓↓↓

兼容到android2.1

我......!!! 那个,请转告老板,把工资给我结一下,谢谢。

我也很绝望啊

可不能这么快就认怂,没有官方的支持,我们就走“曲线救国”爬坑之路呗。虽然实现起来有些麻烦,但也没那么可怕,下面正式进入主题。


ActivityA跳转至ActivityB

简述流程

  1. 获取ActivityA元素信息(如View的大小,位置,id)即属性值材料,作为转场动画的初始值
  2. ActivityA通过Intent传递给ActivityB
  3. ActivityB设为全透明(Window和Content Layout以及元素View皆为透明)
  4. ActivityB读取Intent中的初始值信息并为其元素准备转场动画
  5. ActivityB执行共享元素转场动画

我们以上述google play的转场动画为例,ActivityA上有个app logo即为ImageViewA,ActivityB的即为ImageViewB,logo图片的资源地址为imgUrl。下面用代码示例走流程:

详细代码流程

1. 获取ActivityA的元素信息

        private Bundle createMaterials(View view) {
            // 位置坐标
            int[] location = new int[2];
            view.getLocationOnScreen(location);
            Bundle b = new Bundle();
            int left = location[0];
            int top = location[1];

            // 宽高大小
            int width = view.getWidth();
            int height = view.getHeight();

            // 传入Bundle
            b.putInt("left", left);
            b.putInt("top", top);
            b.putInt("width", width);
            b.putInt("height", height);
            return b;
        }

2. 在ActivityA中构建Intent

        // 获取初始值材料
        Bundle materials=createMaterials(imageViewA);

        Intent intent = new Intent(activityA, ActivityB.class);
        intent.putExtra(EXTRA_IMG_URL, imgUrl);

        // 传入构建好的View属性值材料
        intent.putExtra(EXTRA_VIEW_ATTRS_MATERIALS , materials);

        startActivity(intent);
        // 禁止系统默认动画
        overridePendingTransition(0, 0);

3. ActivityB设为全透明

  • Window设为透明,在ActivityB主题(style)中设置
        <style name="WindowTransparent" parent="AppTheme">
            <item name="android:windowIsTranslucent">true</item>
            <item name="android:windowBackground">@android:color/transparent</item>
        </style>
  • Layout以及元素View设为透明
        <?xml version="1.0" encoding="utf-8"?>
        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/iv_head"
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:scaleType="centerCrop"
                android:visibility="invisible"/>

        </LinearLayout>

4. ActivityB读取Intent转场信息

        private void prepareTransition() {

            int[] location = new int[2];
            imageViewB.getLocationOnScreen(location);

            // 移动到ActivityA元素imageViewA同样的位置   
            deltaX = imageViewALeft - location[0];
            deltaY = imageViewATop - location[1];
            imageViewB.setTranslationX(deltaX);
            imageViewB.setTranslationY(deltaY);

            // 缩放到imageViewA同样的大小
            scaleX = (float) imageViewAWidth / imageViewB.getWidth();
            scaleY = (float) imageViewAHeight / imageViewB.getHeight();
            imageViewB.setScaleX(scaleX);
            imageViewB.setScaleY(scaleY);
        }

5. ActivityB执行共享元素转场动画

        private void runEnterAnimation() {

                imageViewB.setVisibility(View.VISIBLE);

                // 加载图片,如Glide
                Glide.with(context).load(imgUrl).into(imageViewB);

                // 执行动画
                imageViewB.animate()
                        .setDuration(DEFAULT_DURATION)
                        .setInterpolator(DEFAULT_INTERPOLATOR)
                        .scaleX(1f)
                        .scaleY(1f)
                        .translationX(0)
                        .translationY(0)
                        .start();
            }

ActivityB回退至ActivityA

流程比较简单,直接上代码喽:

        private void runExitAnimation() {

                // 执行回退动画
                imageViewB.animate()
                        .setDuration(DEFAULT_DURATION)
                        .setInterpolator(DEFAULT_INTERPOLATOR)
                        .scaleX(scaleX)
                        .scaleY(scaleY)
                        .translationX(deltaX)
                        .translationY(deltaY)
                        .withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                // 关闭ActivityB
                                finish();
                                // 禁止系统默认动画
                                overridePendingTransition(0, 0);
                            }
                        }).start();
            }

OK,大体流程如上,Demo效果图如下:

效果图


如果想深入地学习,大家可以了解下我的开源库,可供学习,亦可集成到项目中使用。

CySharedElementTransition

A compat library of android shared-element transition for lower api.
一个为Android较低版本api提供Android共享元素转场动画的兼容库。

开源库地址:https://github.com/ausboyue/CySharedElementTransition

ScreenShot

easytransition

Download from Gradle

Add to your root build.gradle:

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}

Add the dependency:

dependencies {
    implementation 'com.github.ausboyue:CySharedElementTransition:1.0.1'
}

Friendly Hints

If you can't download it, maybe you have used the Google's repository that you can't connect to the Google server.Please open the proxy or top the target repository.As follows(如果你无法下载这个库,你可能使用了google的仓库。请开启代理或者置顶目标仓库,如下所示):

allprojects {
    repositories {
        maven { url 'https://jitpack.io' } // target repository,be top
        jcenter()
        google() // Google's repository
    }
}

Download from Maven

Add the JitPack repository to your build file:

<repositories>
    <repository>
        <id>jitpack.io</id>
        <url>https://jitpack.io</url>
    </repository>
</repositories>

Add the dependency:

<dependency>
    <groupId>com.github.ausboyue</groupId>
    <artifactId>CySharedElementTransition</artifactId>
    <version>1.0.1</version>
</dependency>

Get Started

1. ActivityA jump to ActivityB,when need use "SharedElementTransition"(ActivityA 跳转到ActivityB,当需要用到“共享元素转场动画”时):

  • ActivityA edit code as below(编辑ActivityA 的代码如下):
    CySharedElementTransition.startActivity(intent, activityA, view1, view2, view...);
  • ActivityB edit code as below(编辑ActivityB 的代码如下):
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ......
        CySharedElementTransition.runEnterAnim(activityB);
        ......
    }

2. ActivityB back to ActivityA(ActivityB Ac回到ActivityA):

  • ActivityB edit code like this(编辑ActivityB 的代码,类似代码如下):
    @Override
    public void onBackPressed() {
        CySharedElementTransition.runExitAnim(activityB);
    }
本文地址:https://www.icheny.cn/archives/850
关注我们:请关注一下微信公众号:扫描二维码乘月网的公众号,公众号:it_place
版权声明:本文为原创文章,版权归 cheny 所有,欢迎分享本文,转载请保留出处!

发表评论


表情