述术

关于Activity跳转动画大汇总

2018-02-01  本文已影响1049人  杨充211

目录介绍

好消息

1.业务需求与实现方法

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

2.业务分析

<?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.具体动画逻辑做法:看具体代码

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);
    }
}
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);
        }
    }
}
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实现切换的方式

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>
/**
 * 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的切换动画

<style name="AnimActivityTheme"  parent="@android:style/Animation.Activity">
    <item name="android:windowAnimationStyle">@style/MyWindowAnimTheme</item>
</style>
<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>
<activity android:name=".MainActivity"
    android:theme="@style/AnimActivityTheme”>

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

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的方式

<explode xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:duration="300" />
<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>
/**
* 点击按钮,实现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动画

<Button
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:text="组件过度动画"
    Android:transitionName="shareNames"/>
<?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>
/**
* 点击按钮,实现Activity的跳转操作
* 通过Android5.0及以上共享组件的方式实现activity的跳转动画
*/
Intent intent = new Intent(MainActivity.this, FiveActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, button, "shareNames").toBundle());

10.其他说明

上一篇下一篇

猜你喜欢

热点阅读