美文网首页述术
关于Activity跳转动画大汇总

关于Activity跳转动画大汇总

作者: 杨充211 | 来源:发表于2018-02-01 19:29 被阅读1049次

    目录介绍

    • 1.业务需求:Activity正反两面,沿中心X,Y轴旋转180度
      • 1.0 具体业务需求
      • 1.1 用3D效果做翻转动画
      • 1.2 用2D效果做翻转动画【实际是缩小-放大,看上去是翻转】
    • 2.业务分析:两个界面放在同一个布局中
      • 2.1 布局设计思路分析
      • 2.2 代码展示
    • 3.具体动画逻辑做法:看具体代码
      • 3.1 定义3D旋转动画
      • 3.2 在activity处理翻转逻辑
      • 3.3 直接展示2D动画实现上面需求的代码
    • 4.关于Activity实现切换的方式
      • 4.1 实现切换的方式
      • 4.2 activity退出动画与显示动画
    • 5.使用overridePendingTransition方法实现Activity跳转动画
      • 5.1 如何实现,步骤演示
      • 5.2 源码分析
    • 6.使用style的方式定义Activity的切换动画
      • 6.1 定义包含动画的 Activity 主题
      • 6.2 定义切换动画 style
      • 6.3 定义具体动画文件
      • 6.4 应用到对应 Activity
      • 6.5 可能出现的bug
        • 6.5.1 添加动画后,出现从黑屏到新activity的过度
        • 6.5.2 没有动画,或动画与设置不一致
    • 7.使用ActivityOptions切换动画实现Activity跳转动画
      • 7.1 这种动画方式介绍
      • 7.2 代码实现方式
    • 8.使用ActivityOptions之后内置的动画效果通过style的方式
      • 8.1 定义动画文件
      • 8.2 定义切换动画style
      • 8.3 执行跳转逻辑
    • 9.使用ActivityOptions动画共享组件的方式实现跳转Activity动画
      • 9.1 定义共享组件
      • 9.2 调用startActivity执行跳转动画
      • 9.3 关于这几种方式的动画总结
    • 10.其他说明
      • 10.1 参考案例
      • 10.2 更新日志
      • 10.3 关于我的博客

    好消息

    • 博客笔记大汇总【16年3月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计47篇[近20万字],转载请注明出处,谢谢!
    • 链接地址:https://github.com/yangchong211/YCBlogs
    • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

    1.业务需求与实现方法

    • 1.0 具体业务需求

      • 这个动画效果是把Activity当做一张纸,正反面都有内容,Activity都会以屏幕中心为翻转中心点(Z轴的翻转中心点可以自由设定),进行旋转。
      • 图形如下所示
    • 1.1 用3D效果做翻转动画

      • 下面2,3均是分析如何实现这种动画
    • 1.2 用2D效果做翻转动画【实际是缩小-放大,看上去是翻转】

      • 比较简单,效果也还不错,直接在看4.3 直接展示2D动画实现上面需求的代码
    • 1.4 代码案例展示

    1.SplashAdFirstActivity,3d效果,沿中心x,y轴旋转,可以设置缩放效果,只需要设置z轴位移就可以
    2.SplashAdSecondActivity,3d效果,借鉴与网络,不是旋转的动画,但是效果很炫
    3.SplashAdThirdActivity,2d效果。看上去像是旋转,实则是缩放效果。几乎看上去效果和1类似
    由于产品需求,后来采用第三种方法
    

    2.业务分析

    • 2.1 布局设计思路分析
      • 这个动画效果的思路是这样的,首先两个界面的布局都在同一个Layout文件中,因为这里只有一个Activity,所以两个界面的布局在同一个layout文件中就要有所设计。
    • 2.2 代码展示
      • 注意,在两个RelativeLayout中必须添加android:focusable=”true” ,android:focusableInTouchMode=”true”这两个属性来隔离两个界面的监听事件,使得当前显示的一面监听有效,另一个不显示的页面的监听无效,否则点击事件会乱套。
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:id="@+id/fl"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <!--启动页-->
        <FrameLayout
            android:id="@+id/fl_ad"
            android:visibility="visible"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <ImageView
                android:id="@+id/iv_ad"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/icon_bg_ad"/>
            <TextView
                android:id="@+id/tv_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="end"
                android:layout_margin="20dp"
                android:padding="5dp"
                android:text="倒计时2秒"
                android:textSize="14sp"
                android:textColor="@color/blackText"
                android:background="@drawable/shape_bg"/>
        </FrameLayout>
    
        <!--主页面-->
        <FrameLayout
            android:id="@+id/fl_main"
            android:visibility="gone"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <include layout="@layout/activity_local_music_info"/>
        </FrameLayout>
    
    </LinearLayout>
    

    3.具体动画逻辑做法:看具体代码

    • 3.1 定义3D旋转动画
      • 翻转效果的设计,首先是确定翻转中心点的位置,通过传入X,Y,Z三个轴的中心点来确定。然后使用Camera根据传入的翻转度来进行翻转,翻转的类Rotate3D代码如下:
    public class Rotate3D extends Animation {
    
        // 开始角度
        private final float mFromDegrees;
        // 结束角度
        private final float mToDegrees;
        // X轴中心点
        private final float mCenterX;
        // Y轴中心点
        private final float mCenterY;
        // Z轴中心点
        private final float mDepthZ;
        //是否需要扭曲
        private final boolean mReverse;
        //摄像头
        private Camera mCamera;
    
        public Rotate3D(float fromDegrees, float toDegrees, float centerX,float centerY, float depthZ, boolean reverse) {
            mFromDegrees = fromDegrees;
            mToDegrees = toDegrees;
            mCenterX = centerX;
            mCenterY = centerY;
            mDepthZ = depthZ;
            mReverse = reverse;
        }
    
        @Override
        public void initialize(int width, int height, int  parentWidth, int parentHeight) {
            super.initialize(width, height, parentWidth, parentHeight);
            mCamera = new Camera();
        }
    
        @Override
        protected void applyTransformation(float interpolatedTime, Transformation t) {
            final float fromDegrees = mFromDegrees;
            // 生成中间角度
            float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
            final float centerX = mCenterX;
            final float centerY = mCenterY;
            final Camera camera = mCamera;
            //取得当前矩阵
            final Matrix matrix = t.getMatrix();
            camera.save();
            if (mReverse) {
                camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
            } else {
                camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
            }
            //翻转
            camera.rotateY(degrees);
            // 取得变换后的矩阵
            camera.getMatrix(matrix);
            camera.restore();
            matrix.preTranslate(-centerX, -centerY);
            matrix.postTranslate(centerX, centerY);
        }
    }
    
    • 3.2 在activity处理翻转逻辑
      • 整个翻转过程分为两个阶段操作,第一阶段是从当前页面翻转到整个Activity垂直于手机屏幕(到这个时刻,正反两面都是不可见的)。第二阶段是从当前的整个Activity垂直于手机屏幕(到这个时刻,正反两面都是不可见的)状态翻转到第二个页面显示在手机屏幕上。
      • 代码如下所示
    public class SplashAdFirstActivity extends BaseActivity {
    
        @Bind(R.id.iv_ad)
        ImageView ivAd;
        @Bind(R.id.tv_time)
        TextView tvTime;
        //页面翻转容器FrameLayout
        @Bind(R.id.fl)
        LinearLayout fl;
        //布局1界面RelativeLayout
        @Bind(R.id.fl_ad)
        FrameLayout flAd;
        //布局2界面RelativeLayout
        @Bind(R.id.fl_main)
        FrameLayout flMain;
        private TimeCount timeCount;
        private boolean isClick = false;
        //z轴翻转
        private float z = 200.0f;
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (timeCount != null) {
                timeCount.cancel();
                timeCount = null;
            }
        }
    
        @Override
        public int getContentView() {
            return R.layout.activity_splash_ad;
        }
    
        @Override
        public void initView() {
            initTimer();
        }
    
        private void initTimer() {
            timeCount = new TimeCount(5 * 1000, 1000, tvTime);
            timeCount.start();
        }
    
        @Override
        public void initListener() {
            ivAd.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    isClick = true;
                    applyRotation(1,0,90);
                    //applyRotation(0,0,-90);
                }
            });
        }
    
        @Override
        public void initData() {
    
        }
    
        private class TimeCount extends CountDownTimer {
    
            private TextView tv;
            TimeCount(long millisInFuture, long countDownInterval, TextView tv) {
                super(millisInFuture, countDownInterval);
                //参数依次为总时长,和计时的时间间隔
                this.tv = tv;
            }
    
            //计时完毕时触发
            @Override
            public void onFinish() {
                //如果是点击了翻转,那么就不执行这里面的代码
                if(!isClick){
                    //第一阶段翻转
                    applyRotation(1,0,90);
                    //applyRotation(0,0,-90);
                }
            }
    
            @Override
            public void onTick(long millisUntilFinished) {
                //计时过程显示
                StringBuilder sb = new StringBuilder();
                sb.append("倒计时");
                sb.append(millisUntilFinished / 1000);
                sb.append("秒");
                tv.setText(sb.toString());
            }
        }
    
        /**
         * 执行翻转第一阶段翻转动画
         * @param tag view索引
         * @param start 起始角度
         * @param end 结束角度
         */
        private void applyRotation(int tag, float start, float end) {
            // 得到中心点(以中心翻转)
            //X轴中心点
            final float centerX = fl.getWidth() / 2.0f;
            //Y轴中心点
            final float centerY = fl.getHeight() / 2.0f;
            //Z轴中心点
            final float depthZ = z;
            // 根据参数创建一个新的三维动画,并且监听触发下一个动画
            final Rotate3D rotation = new Rotate3D(start, end, centerX, centerY, depthZ, true);
            //设置动画持续时间
            rotation.setDuration(2500);
            //设置动画变化速度
            //rotation.setInterpolator(new AccelerateInterpolator());
            //设置第一阶段动画监听器
            rotation.setAnimationListener(new DisplayNextView(tag));
            fl.startAnimation(rotation);
        }
    
    
        /**
         * 第一阶段动画监听器
         */
        private final class DisplayNextView implements Animation.AnimationListener {
            private final int tag;
    
            private DisplayNextView(int tag) {
                this.tag = tag;
            }
    
            @Override
            public void onAnimationStart(Animation animation) {}
    
            @Override
            public void onAnimationEnd(Animation animation) {
                //第一阶段动画结束时,也就是整个Activity垂直于手机屏幕,
                //执行第二阶段动画
                fl.post(new SwapViews(tag));
                //调整两个界面各自的visibility
                adjustVisibility();
            }
    
            @Override
            public void onAnimationRepeat(Animation animation) {
            }
        }
    
    
        /**
         * 执行翻转第二个阶段动画
         */
        private final class SwapViews implements Runnable {
    
            private final int tag;
            SwapViews(int position) {
                tag = position;
            }
            @Override
            public void run() {
                if (tag == 0) {
                    //首页页面以90~0度翻转
                    showView(flAd, flMain, 90, 0);
                } else if (tag == 1) {
                    //音乐页面以-90~0度翻转
                    showView(flMain, flAd, -90, 0);
                }
            }
        }
    
        /**
         * 显示第二个视图动画
         * @param showView 要显示的视图
         * @param hiddenView 要隐藏的视图
         * @param startDegree 开始角度
         * @param endDegree 目标角度
         */
        private void showView(FrameLayout showView, FrameLayout hiddenView, int startDegree, int endDegree) {
            //同样以中心点进行翻转
            float centerX = showView.getWidth() / 2.0f;
            float centerY = showView.getHeight() / 2.0f;
            float centerZ = z;
            if (centerX == 0 || centerY == 0) {
                //调用该方法getMeasuredWidth(),必须先执行measure()方法,否则会出异常。
                showView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
                //获取该view在父容器里面占的大小
                centerX = showView.getMeasuredWidth() / 2.0f;
                centerY = showView.getMeasuredHeight() / 2.0f;
            }
            hiddenView.setVisibility(View.GONE);
            showView.setVisibility(View.VISIBLE);
            Rotate3D rotation = new Rotate3D(startDegree, endDegree, centerX, centerY, centerZ, true);
            //设置动画持续时间
            rotation.setDuration(2500);
            //设置动画变化速度
            //rotation.setInterpolator(new DecelerateInterpolator());
            fl.startAnimation(rotation);
        }
    
    
        /**
         * 两个布局的visibility调节
         */
        private void adjustVisibility(){
            if(flAd.getVisibility() == View.VISIBLE){
                flAd.setVisibility(View.GONE);
            }else {
                flMain.setVisibility(View.VISIBLE);
            }
            if(flMain.getVisibility() == View.VISIBLE){
                flMain.setVisibility(View.GONE);
            }else {
                flAd.setVisibility(View.VISIBLE);
            }
        }
    }
    
    • 3.3 直接展示2D动画实现上面需求的代码
    public class SplashAdThirdActivity extends BaseActivity {
    
        @Bind(R.id.fl_ad)
        FrameLayout flAd;
        @Bind(R.id.fl_main)
        FrameLayout flMain;
        @Bind(R.id.fl)
        LinearLayout fl;
        @Bind(R.id.iv_ad)
        ImageView ivAd;
        @Bind(R.id.tv_time)
        TextView tvTime;
    
    
        private TimeCount timeCount;
        private boolean isClick = false;
    
        private ScaleAnimation sato0 = new ScaleAnimation(1,0,1,1,
                Animation.RELATIVE_TO_PARENT,0.5f, Animation.RELATIVE_TO_PARENT,0.5f);
    
        private ScaleAnimation sato1 = new ScaleAnimation(0,1,1,1,
                Animation.RELATIVE_TO_PARENT,0.5f,Animation.RELATIVE_TO_PARENT,0.5f);
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (timeCount != null) {
                timeCount.cancel();
                timeCount = null;
            }
        }
    
        @Override
        public int getContentView() {
            return R.layout.activity_splash_ad;
        }
    
        @Override
        public void initView() {
            initTimer();
        }
    
        private void initTimer() {
            timeCount = new TimeCount(5 * 1000, 1000, tvTime);
            timeCount.start();
        }
    
        @Override
        public void initListener() {
            ivAd.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    isClick = true;
                    flAd.startAnimation(sato0);
                }
            });
        }
    
        @Override
        public void initData() {
            showView1();
            sato0.setDuration(500);
            sato1.setDuration(500);
            sato0.setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
    
                }
    
                @Override
                public void onAnimationEnd(Animation animation) {
                    if (flAd.getVisibility() == View.VISIBLE){
                        flAd.setAnimation(null);
                        showView2();
                        flMain.startAnimation(sato1);
                    }else{
                        flMain.setAnimation(null);
                        showView1();
                        flAd.startAnimation(sato1);
                    }
                }
    
                @Override
                public void onAnimationRepeat(Animation animation) {
    
                }
            });
        }
    
        private class TimeCount extends CountDownTimer {
    
            private TextView tv;
    
            TimeCount(long millisInFuture, long countDownInterval, TextView tv) {
                super(millisInFuture, countDownInterval);
                //参数依次为总时长,和计时的时间间隔
                this.tv = tv;
            }
    
            //计时完毕时触发
            @Override
            public void onFinish() {
                //如果是点击了翻转,那么就不执行这里面的代码
                if(!isClick){
                    //第一阶段翻转
                    flAd.startAnimation(sato0);
                }
            }
    
            @Override
            public void onTick(long millisUntilFinished) {
                //计时过程显示
                StringBuilder sb = new StringBuilder();
                sb.append("倒计时");
                sb.append(millisUntilFinished / 1000);
                sb.append("秒");
                tv.setText(sb.toString());
            }
        }
    
        private void showView1(){
            flAd.setVisibility(View.VISIBLE);
            flMain.setVisibility(View.GONE);
        }
    
        private void showView2(){
            flAd.setVisibility(View.GONE);
            flMain.setVisibility(View.VISIBLE);
        }
    }
    

    4.关于Activity实现切换的方式

    • 4.1 实现切换的方式
      • 调用startActivity方法启动一个新的Activity并跳转其页面
      • 调用finish方法销毁当前的Activity返回上一个Activity界面
    • 4.2 activity退出动画与显示动画
      • 当调用startActivity方法的时候启动一个新的activity,这时候就涉及到了旧的Activity的退出动画和新的Activity的显示动画;
      • 当调用finish方法的时候,销毁当前Acitivity,就涉及到了当前Activity的退出动画和前一个Activity的显示动画;
      • 所以我们的activity跳转动画是分为两个部分的:一个Activity的销毁动画与一个Activity的显示动画,明白了这一点之后我们开始看一下第一种实现Activity跳转动画的方式:通过overridePendingTransition方法实现Activity切换动画。

    5.使用overridePendingTransition方法实现Activity跳转动画

    Intent intent = new Intent(this, MainActivity.class);
    startActivity(intent);
    overridePendingTransition(R.anim.screen_zoom_in, R.anim.screen_zoom_out);
    finish();
    
    • 动画代码如下所示
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"
        android:interpolator="@android:anim/accelerate_interpolator">
        <scale
            android:duration="@android:integer/config_mediumAnimTime"
            android:fromXScale="2.0"
            android:fromYScale="2.0"
            android:pivotX="50%p"
            android:pivotY="50%p"
            android:toXScale="1.0"
            android:toYScale="1.0" />
    
        <alpha
            android:duration="@android:integer/config_mediumAnimTime"
            android:fromAlpha="0"
            android:toAlpha="1.0" />
    </set>
    
    • 5.2 源码分析
      • 看下面这一段注释可以知道:
        • overridePendingTransition方法需要在startAtivity方法或者是finish方法调用之后立即执行
        • 参数enterAnim表示的是从Activity a跳转到Activity b,进入b时的动画效果
        • 参数exitAnim表示的是从Activity a跳转到Activity b,离开a时的动过效果
        • 若进入b或者是离开a时不需要动画效果,则可以传值为0
    /**
     * Call immediately after one of the flavors of {@link #startActivity(Intent)}
     * or {@link #finish} to specify an explicit transition animation to
     * perform next.
     *
     * <p>As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN} an alternative
     * to using this with starting activities is to supply the desired animation
     * information through a {@link ActivityOptions} bundle to
     * {@link #startActivity(Intent, Bundle)} or a related function.  This allows
     * you to specify a custom animation even when starting an activity from
     * outside the context of the current top activity.
     *
     * @param enterAnim A resource ID of the animation resource to use for
     * the incoming activity.  Use 0 for no animation.
     * @param exitAnim A resource ID of the animation resource to use for
     * the outgoing activity.  Use 0 for no animation.
     */
    public void overridePendingTransition(int enterAnim, int exitAnim) {
        try {
            ActivityManagerNative.getDefault().overridePendingTransition(
                    mToken, getPackageName(), enterAnim, exitAnim);
        } catch (RemoteException e) {
        }
    }
    

    6.使用style的方式定义Activity的切换动画

    • 6.1 定义包含动画的 Activity 主题
      • 在res/values/styles.xml文件中
    <style name="AnimActivityTheme"  parent="@android:style/Animation.Activity">
        <item name="android:windowAnimationStyle">@style/MyWindowAnimTheme</item>
    </style>
    
    • 6.2 定义切换动画 style
      • 还是res/values/styles.xml 文件中
        • activityOpenEnterAnimation // 用于设置打开新的Activity并进入新的Activity展示的动画
        • activityOpenExitAnimation // 用于设置打开新的Activity并销毁之前的Activity展示的动画
        • activityCloseEnterAnimation // 用于设置关闭当前Activity进入上一个Activity展示的动画
        • activityCloseExitAnimation // 用于设置关闭当前Activity时展示的动画
    <style name="MyWindowAnimTheme">
        <item name="android:activityOpenEnterAnimation">@anim/top_to_bottom_in</item>
        <item name="android:activityOpenExitAnimation">@anim/top_to_bottom_out</item>
        <item name="android:activityCloseEnterAnimation">@anim/bottom_to_top_in</item>
        <item name="android:activityCloseExitAnimation">@anim/bottom_to_top_out</item>
    </style>
    
    • 6.3 定义具体动画文件

      • res/anmi/res/top_to_bottom_in.xml
      • res/anmi/res/top_to_bottom_out.xml
      • res/anmi/res/bottom_to_top_in.xml
      • res/anmi/res/bottom_to_top_out.xml
    • 6.4 应用到对应 Activity

      • 在清单文件中添加
    <activity android:name=".MainActivity"
        android:theme="@style/AnimActivityTheme”>
    
    • 6.5 可能出现的bug
      • 6.5.1 添加动画后,出现从黑屏到新activity的过度
        • 问题:添加动画后,出现从黑屏到新activity的过度。
        • 原因:没有设置相应的消失动画。
        • 解决方法:设置相应的消失动画,如果不想设置消失动画,可以使用写一个假动画,这个动画是没有任何效果,只是为了避免出现黑屏,运行效果为原acticity静止不动,新启动的activity执行进入动画。
      • 6.5.2 没有动画,或动画与设置不一致
        • 问题:没有动画,或动画与设置不一致
        • 原因:当页面切换时需要进入和消失两个动画,当没有进入动画时,消失动画也不会执行,会执行系统动画,如果没有系统动画则没有动画,或者某个页面使用第一或第二种方式设置了动画(动画执行优先级,系统动画 < AppTheme < (overridePendingTransition\ActivityOptionsCompat))。
        • 解决方法:为了保证进入和消失都有动画,要将动画主题设置到两个Activity上。也可以将主题设置到application上,这样整个应用都是用该切换动画。如果是某个页面使用第一或第二种方式设置了动画,那么在启动和退出时最好都要设置,不然会造成启动和退出不一致的情况。

    7.使用ActivityOptions切换动画实现Activity跳转动画

    • 7.1 这种动画方式介绍
      • 上面我们讲解的通过overridePendingTransition方法基本上可以满足我们日常中对Activity跳转动画的需求了,但是MD风格出来之后,overridePendingTransition这种老旧、生硬的方式怎么能适合我们的MD风格的App呢?好在google在新的sdk中给我们提供了另外一种Activity的过度动画——ActivityOptions。并且提供了兼容包——ActivityOptionsCompat。ActivityOptionsCompat是一个静态类,提供了相应的Activity跳转动画效果,通过其可以实现不少炫酷的动画效果。
    • 7.2 代码实现方式
      • 代码诠释
        • 传入了ActivityOptions.makeSceneTransitionAnimation,该方法表示将Activity a平滑的切换到Activity b,其还有几个重载方法可以指定相关的View,即以View为焦点平滑的从Activity a切换到Activity b。
        • 这里的setFeature就是为activity的窗口设置特性,不同的特性对应不同的布局方式,比如可以设置无toolbar模式,有toolbar模式等等。而这里设置的是需要过渡动画,并且我们获取了Android中内置的explode动画,并设值给了Activity的window窗口对象,这样当Activity被启动的时候就会执行explode所带便的动画效果了。
      • 在startActivity页面
    Intent intent = new Intent(MainActivity.this, ThreeActivity.class);
    startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());
    
    • 在跳转后的页面
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        // 设置contentFeature,可使用切换动画
        getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
        Transition explode = TransitionInflater.from(this).inflateTransition(Android.R.transition.explode);
        getWindow().setEnterTransition(explode);
    
        setContentView(R.layout.activity_main);
    }
    

    8.使用ActivityOptions之后内置的动画效果通过style的方式

    • 8.1 定义动画文件
      • 这种方式其实就是通过style的方式展示和使用ActivityOptions过度动画,下面是实现通过定义style方式定义过度动画的步骤:
      • res目录下新建一个transition目录,然后创建资源文件,然后使用这些系统自带的过渡动画效果,这里设置了过度时长为300ms
    <explode xmlns:Android="http://schemas.Android.com/apk/res/Android"
        Android:duration="300" />
    
    • 8.2 定义切换动画style
    <style name="AppAnimTheme">
        <item name="Android:windowEnterTransition">@transition/activity_explode</item>
        <item name="Android:windowExitTransition">@transition/activity_explode</item>
    </style>
    
    <item name="Android:windowEnterTransition">@transition/activity_explode</item>
    <item name="Android:windowExitTransition">@transition/activity_explode</item>
    
    • 8.3 执行跳转逻辑
    /**
    * 点击按钮,实现Activity的跳转操作
    * 通过Android5.0及以上style的方式实现activity的跳转动画
    */
    /**
    * 调用ActivityOptions.makeSceneTransitionAnimation实现过度动画
    */
    Intent intent = new Intent(MainActivity.this, FourActivity.class);
    startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());
    

    9.使用ActivityOptions动画共享组件的方式实现跳转Activity动画

    • 这里的共享组件动画效果是指将前面一个Activity的某个子View与后面一个Activity的某个子View之间有过渡效果,即在这种过度效果下实现Activity的跳转操作。那么如何实现两个组件View之间实现过渡效果呢?
    • 9.1 定义共享组件
      • 在Activity a中的button按钮点击transitionName属性:
    <Button
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:text="组件过度动画"
        Android:transitionName="shareNames"/>
    
    • 在Activity b的布局文件中为组件定义transitionName属性,这样这两个组件相当于有了过度对应关系,这里需要注意的是这两个组件的transitionName属性的值必须是相同的。
    <?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:orientation="vertical"
        Android:transitionName="shareNames">
    </LinearLayout>
    
    • 9.2 调用startActivity执行跳转动画
      • 需要说明的是这里调用的ActivityOptions.makeSceneTransitionAnimation方法,传递了三个参数,其中第一个参数为context对象,第二个参数为启动Activity的共享组件,第三个参数为启动Activity的共享组件transitionName属性值。
    /**
    * 点击按钮,实现Activity的跳转操作
    * 通过Android5.0及以上共享组件的方式实现activity的跳转动画
    */
    Intent intent = new Intent(MainActivity.this, FiveActivity.class);
    startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, button, "shareNames").toBundle());
    
    • 9.3 关于这几种方式的动画总结
      • 通过overridePendingTransition方式和ActivityOptions动画API实现Activity的切换动画效果;
      • overridePendingTransition方法从Android2.0开始,基本上能够覆盖我们activity跳转动画的需求;
      • ActivityOptions API是在Android5.0开始的,可以实现一些炫酷的动画效果,更加符合MD风格;
      • ActivityOptions还可以实现两个Activity组件之间的过度动画;

    10.其他说明

    相关文章

      网友评论

        本文标题:关于Activity跳转动画大汇总

        本文链接:https://www.haomeiwen.com/subject/ehljzxtx.html