關(guān)于Activity跳轉(zhuǎn)動(dòng)畫(huà)大匯總

目錄介紹

  • 1.業(yè)務(wù)需求:Activity正反兩面荸恕,沿中心X,Y軸旋轉(zhuǎn)180度
    • 1.0 具體業(yè)務(wù)需求
    • 1.1 用3D效果做翻轉(zhuǎn)動(dòng)畫(huà)
    • 1.2 用2D效果做翻轉(zhuǎn)動(dòng)畫(huà)【實(shí)際是縮小-放大越妈,看上去是翻轉(zhuǎn)】
  • 2.業(yè)務(wù)分析:兩個(gè)界面放在同一個(gè)布局中
    • 2.1 布局設(shè)計(jì)思路分析
    • 2.2 代碼展示
  • 3.具體動(dòng)畫(huà)邏輯做法:看具體代碼
    • 3.1 定義3D旋轉(zhuǎn)動(dòng)畫(huà)
    • 3.2 在activity處理翻轉(zhuǎn)邏輯
    • 3.3 直接展示2D動(dòng)畫(huà)實(shí)現(xiàn)上面需求的代碼
  • 4.關(guān)于Activity實(shí)現(xiàn)切換的方式
    • 4.1 實(shí)現(xiàn)切換的方式
    • 4.2 activity退出動(dòng)畫(huà)與顯示動(dòng)畫(huà)
  • 5.使用overridePendingTransition方法實(shí)現(xiàn)Activity跳轉(zhuǎn)動(dòng)畫(huà)
    • 5.1 如何實(shí)現(xiàn)袖迎,步驟演示
    • 5.2 源碼分析
  • 6.使用style的方式定義Activity的切換動(dòng)畫(huà)
    • 6.1 定義包含動(dòng)畫(huà)的 Activity 主題
    • 6.2 定義切換動(dòng)畫(huà) style
    • 6.3 定義具體動(dòng)畫(huà)文件
    • 6.4 應(yīng)用到對(duì)應(yīng) Activity
    • 6.5 可能出現(xiàn)的bug
      • 6.5.1 添加動(dòng)畫(huà)后,出現(xiàn)從黑屏到新activity的過(guò)度
      • 6.5.2 沒(méi)有動(dòng)畫(huà)践宴,或動(dòng)畫(huà)與設(shè)置不一致
  • 7.使用ActivityOptions切換動(dòng)畫(huà)實(shí)現(xiàn)Activity跳轉(zhuǎn)動(dòng)畫(huà)
    • 7.1 這種動(dòng)畫(huà)方式介紹
    • 7.2 代碼實(shí)現(xiàn)方式
  • 8.使用ActivityOptions之后內(nèi)置的動(dòng)畫(huà)效果通過(guò)style的方式
    • 8.1 定義動(dòng)畫(huà)文件
    • 8.2 定義切換動(dòng)畫(huà)style
    • 8.3 執(zhí)行跳轉(zhuǎn)邏輯
  • 9.使用ActivityOptions動(dòng)畫(huà)共享組件的方式實(shí)現(xiàn)跳轉(zhuǎn)Activity動(dòng)畫(huà)
    • 9.1 定義共享組件
    • 9.2 調(diào)用startActivity執(zhí)行跳轉(zhuǎn)動(dòng)畫(huà)
    • 9.3 關(guān)于這幾種方式的動(dòng)畫(huà)總結(jié)
  • 10.其他說(shuō)明
    • 10.1 參考案例
    • 10.2 更新日志
    • 10.3 關(guān)于我的博客

好消息

  • 博客筆記大匯總【16年3月到至今】陨囊,包括Java基礎(chǔ)及深入知識(shí)點(diǎn),Android技術(shù)博客剧辐,Python學(xué)習(xí)筆記等等寒亥,還包括平時(shí)開(kāi)發(fā)中遇到的bug匯總,當(dāng)然也在工作之余收集了大量的面試題荧关,長(zhǎng)期更新維護(hù)并且修正溉奕,持續(xù)完善……開(kāi)源的文件是markdown格式的!同時(shí)也開(kāi)源了生活博客忍啤,從12年起加勤,積累共計(jì)47篇[近20萬(wàn)字],轉(zhuǎn)載請(qǐng)注明出處同波,謝謝鳄梅!
  • 鏈接地址:https://github.com/yangchong211/YCBlogs
  • 如果覺(jué)得好,可以star一下未檩,謝謝卫枝!當(dāng)然也歡迎提出建議,萬(wàn)事起于忽微讹挎,量變引起質(zhì)變校赤!

1.業(yè)務(wù)需求與實(shí)現(xiàn)方法

  • 1.0 具體業(yè)務(wù)需求

    • 這個(gè)動(dòng)畫(huà)效果是把Activity當(dāng)做一張紙吆玖,正反面都有內(nèi)容,Activity都會(huì)以屏幕中心為翻轉(zhuǎn)中心點(diǎn)(Z軸的翻轉(zhuǎn)中心點(diǎn)可以自由設(shè)定)马篮,進(jìn)行旋轉(zhuǎn)沾乘。
    • 圖形如下所示
  • 1.1 用3D效果做翻轉(zhuǎn)動(dòng)畫(huà)

    • 下面2,3均是分析如何實(shí)現(xiàn)這種動(dòng)畫(huà)
  • 1.2 用2D效果做翻轉(zhuǎn)動(dòng)畫(huà)【實(shí)際是縮小-放大浑测,看上去是翻轉(zhuǎn)】

    • 比較簡(jiǎn)單翅阵,效果也還不錯(cuò),直接在看4.3 直接展示2D動(dòng)畫(huà)實(shí)現(xiàn)上面需求的代碼
  • 1.4 代碼案例展示

1.SplashAdFirstActivity迁央,3d效果掷匠,沿中心x,y軸旋轉(zhuǎn)岖圈,可以設(shè)置縮放效果讹语,只需要設(shè)置z軸位移就可以
2.SplashAdSecondActivity,3d效果蜂科,借鑒與網(wǎng)絡(luò)顽决,不是旋轉(zhuǎn)的動(dòng)畫(huà),但是效果很炫
3.SplashAdThirdActivity导匣,2d效果才菠。看上去像是旋轉(zhuǎn)贡定,實(shí)則是縮放效果赋访。幾乎看上去效果和1類(lèi)似
由于產(chǎn)品需求,后來(lái)采用第三種方法

2.業(yè)務(wù)分析

  • 2.1 布局設(shè)計(jì)思路分析
    • 這個(gè)動(dòng)畫(huà)效果的思路是這樣的缓待,首先兩個(gè)界面的布局都在同一個(gè)Layout文件中蚓耽,因?yàn)檫@里只有一個(gè)Activity,所以?xún)蓚€(gè)界面的布局在同一個(gè)layout文件中就要有所設(shè)計(jì)命斧。
  • 2.2 代碼展示
    • 注意,在兩個(gè)RelativeLayout中必須添加android:focusable=”true” 嘱兼,android:focusableInTouchMode=”true”這兩個(gè)屬性來(lái)隔離兩個(gè)界面的監(jiān)聽(tīng)事件国葬,使得當(dāng)前顯示的一面監(jiān)聽(tīng)有效,另一個(gè)不顯示的頁(yè)面的監(jiān)聽(tīng)無(wú)效芹壕,否則點(diǎn)擊事件會(huì)亂套汇四。
<?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">

    <!--啟動(dòng)頁(yè)-->
    <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="倒計(jì)時(shí)2秒"
            android:textSize="14sp"
            android:textColor="@color/blackText"
            android:background="@drawable/shape_bg"/>
    </FrameLayout>

    <!--主頁(yè)面-->
    <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.具體動(dòng)畫(huà)邏輯做法:看具體代碼

  • 3.1 定義3D旋轉(zhuǎn)動(dòng)畫(huà)
    • 翻轉(zhuǎn)效果的設(shè)計(jì),首先是確定翻轉(zhuǎn)中心點(diǎn)的位置踢涌,通過(guò)傳入X,Y,Z三個(gè)軸的中心點(diǎn)來(lái)確定通孽。然后使用Camera根據(jù)傳入的翻轉(zhuǎn)度來(lái)進(jìn)行翻轉(zhuǎn),翻轉(zhuǎn)的類(lèi)Rotate3D代碼如下:
public class Rotate3D extends Animation {

    // 開(kāi)始角度
    private final float mFromDegrees;
    // 結(jié)束角度
    private final float mToDegrees;
    // X軸中心點(diǎn)
    private final float mCenterX;
    // Y軸中心點(diǎn)
    private final float mCenterY;
    // Z軸中心點(diǎn)
    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;
        //取得當(dāng)前矩陣
        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));
        }
        //翻轉(zhuǎn)
        camera.rotateY(degrees);
        // 取得變換后的矩陣
        camera.getMatrix(matrix);
        camera.restore();
        matrix.preTranslate(-centerX, -centerY);
        matrix.postTranslate(centerX, centerY);
    }
}
  • 3.2 在activity處理翻轉(zhuǎn)邏輯
    • 整個(gè)翻轉(zhuǎn)過(guò)程分為兩個(gè)階段操作睁壁,第一階段是從當(dāng)前頁(yè)面翻轉(zhuǎn)到整個(gè)Activity垂直于手機(jī)屏幕(到這個(gè)時(shí)刻背苦,正反兩面都是不可見(jiàn)的)互捌。第二階段是從當(dāng)前的整個(gè)Activity垂直于手機(jī)屏幕(到這個(gè)時(shí)刻,正反兩面都是不可見(jiàn)的)狀態(tài)翻轉(zhuǎn)到第二個(gè)頁(yè)面顯示在手機(jī)屏幕上行剂。
    • 代碼如下所示
public class SplashAdFirstActivity extends BaseActivity {

    @Bind(R.id.iv_ad)
    ImageView ivAd;
    @Bind(R.id.tv_time)
    TextView tvTime;
    //頁(yè)面翻轉(zhuǎn)容器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軸翻轉(zhuǎn)
    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);
            //參數(shù)依次為總時(shí)長(zhǎng),和計(jì)時(shí)的時(shí)間間隔
            this.tv = tv;
        }

        //計(jì)時(shí)完畢時(shí)觸發(fā)
        @Override
        public void onFinish() {
            //如果是點(diǎn)擊了翻轉(zhuǎn)秕噪,那么就不執(zhí)行這里面的代碼
            if(!isClick){
                //第一階段翻轉(zhuǎn)
                applyRotation(1,0,90);
                //applyRotation(0,0,-90);
            }
        }

        @Override
        public void onTick(long millisUntilFinished) {
            //計(jì)時(shí)過(guò)程顯示
            StringBuilder sb = new StringBuilder();
            sb.append("倒計(jì)時(shí)");
            sb.append(millisUntilFinished / 1000);
            sb.append("秒");
            tv.setText(sb.toString());
        }
    }

    /**
     * 執(zhí)行翻轉(zhuǎn)第一階段翻轉(zhuǎn)動(dòng)畫(huà)
     * @param tag view索引
     * @param start 起始角度
     * @param end 結(jié)束角度
     */
    private void applyRotation(int tag, float start, float end) {
        // 得到中心點(diǎn)(以中心翻轉(zhuǎn))
        //X軸中心點(diǎn)
        final float centerX = fl.getWidth() / 2.0f;
        //Y軸中心點(diǎn)
        final float centerY = fl.getHeight() / 2.0f;
        //Z軸中心點(diǎn)
        final float depthZ = z;
        // 根據(jù)參數(shù)創(chuàng)建一個(gè)新的三維動(dòng)畫(huà),并且監(jiān)聽(tīng)觸發(fā)下一個(gè)動(dòng)畫(huà)
        final Rotate3D rotation = new Rotate3D(start, end, centerX, centerY, depthZ, true);
        //設(shè)置動(dòng)畫(huà)持續(xù)時(shí)間
        rotation.setDuration(2500);
        //設(shè)置動(dòng)畫(huà)變化速度
        //rotation.setInterpolator(new AccelerateInterpolator());
        //設(shè)置第一階段動(dòng)畫(huà)監(jiān)聽(tīng)器
        rotation.setAnimationListener(new DisplayNextView(tag));
        fl.startAnimation(rotation);
    }


    /**
     * 第一階段動(dòng)畫(huà)監(jiān)聽(tīng)器
     */
    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) {
            //第一階段動(dòng)畫(huà)結(jié)束時(shí),也就是整個(gè)Activity垂直于手機(jī)屏幕厚宰,
            //執(zhí)行第二階段動(dòng)畫(huà)
            fl.post(new SwapViews(tag));
            //調(diào)整兩個(gè)界面各自的visibility
            adjustVisibility();
        }

        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    }


    /**
     * 執(zhí)行翻轉(zhuǎn)第二個(gè)階段動(dòng)畫(huà)
     */
    private final class SwapViews implements Runnable {

        private final int tag;
        SwapViews(int position) {
            tag = position;
        }
        @Override
        public void run() {
            if (tag == 0) {
                //首頁(yè)頁(yè)面以90~0度翻轉(zhuǎn)
                showView(flAd, flMain, 90, 0);
            } else if (tag == 1) {
                //音樂(lè)頁(yè)面以-90~0度翻轉(zhuǎn)
                showView(flMain, flAd, -90, 0);
            }
        }
    }

    /**
     * 顯示第二個(gè)視圖動(dòng)畫(huà)
     * @param showView 要顯示的視圖
     * @param hiddenView 要隱藏的視圖
     * @param startDegree 開(kāi)始角度
     * @param endDegree 目標(biāo)角度
     */
    private void showView(FrameLayout showView, FrameLayout hiddenView, int startDegree, int endDegree) {
        //同樣以中心點(diǎn)進(jìn)行翻轉(zhuǎn)
        float centerX = showView.getWidth() / 2.0f;
        float centerY = showView.getHeight() / 2.0f;
        float centerZ = z;
        if (centerX == 0 || centerY == 0) {
            //調(diào)用該方法getMeasuredWidth()腌巾,必須先執(zhí)行measure()方法,否則會(huì)出異常铲觉。
            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);
        //設(shè)置動(dòng)畫(huà)持續(xù)時(shí)間
        rotation.setDuration(2500);
        //設(shè)置動(dòng)畫(huà)變化速度
        //rotation.setInterpolator(new DecelerateInterpolator());
        fl.startAnimation(rotation);
    }


    /**
     * 兩個(gè)布局的visibility調(diào)節(jié)
     */
    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動(dòng)畫(huà)實(shí)現(xiàn)上面需求的代碼
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);
            //參數(shù)依次為總時(shí)長(zhǎng),和計(jì)時(shí)的時(shí)間間隔
            this.tv = tv;
        }

        //計(jì)時(shí)完畢時(shí)觸發(fā)
        @Override
        public void onFinish() {
            //如果是點(diǎn)擊了翻轉(zhuǎn)澈蝙,那么就不執(zhí)行這里面的代碼
            if(!isClick){
                //第一階段翻轉(zhuǎn)
                flAd.startAnimation(sato0);
            }
        }

        @Override
        public void onTick(long millisUntilFinished) {
            //計(jì)時(shí)過(guò)程顯示
            StringBuilder sb = new StringBuilder();
            sb.append("倒計(jì)時(shí)");
            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.關(guān)于Activity實(shí)現(xiàn)切換的方式

  • 4.1 實(shí)現(xiàn)切換的方式
    • 調(diào)用startActivity方法啟動(dòng)一個(gè)新的Activity并跳轉(zhuǎn)其頁(yè)面
    • 調(diào)用finish方法銷(xiāo)毀當(dāng)前的Activity返回上一個(gè)Activity界面
  • 4.2 activity退出動(dòng)畫(huà)與顯示動(dòng)畫(huà)
    • 當(dāng)調(diào)用startActivity方法的時(shí)候啟動(dòng)一個(gè)新的activity,這時(shí)候就涉及到了舊的Activity的退出動(dòng)畫(huà)和新的Activity的顯示動(dòng)畫(huà)撵幽;
    • 當(dāng)調(diào)用finish方法的時(shí)候灯荧,銷(xiāo)毀當(dāng)前Acitivity,就涉及到了當(dāng)前Activity的退出動(dòng)畫(huà)和前一個(gè)Activity的顯示動(dòng)畫(huà)并齐;
    • 所以我們的activity跳轉(zhuǎn)動(dòng)畫(huà)是分為兩個(gè)部分的:一個(gè)Activity的銷(xiāo)毀動(dòng)畫(huà)與一個(gè)Activity的顯示動(dòng)畫(huà)漏麦,明白了這一點(diǎn)之后我們開(kāi)始看一下第一種實(shí)現(xiàn)Activity跳轉(zhuǎn)動(dòng)畫(huà)的方式:通過(guò)overridePendingTransition方法實(shí)現(xiàn)Activity切換動(dòng)畫(huà)。

5.使用overridePendingTransition方法實(shí)現(xiàn)Activity跳轉(zhuǎn)動(dòng)畫(huà)

Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.screen_zoom_in, R.anim.screen_zoom_out);
finish();
  • 動(dòng)畫(huà)代碼如下所示
<?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方法調(diào)用之后立即執(zhí)行
      • 參數(shù)enterAnim表示的是從Activity a跳轉(zhuǎn)到Activity b测垛,進(jìn)入b時(shí)的動(dòng)畫(huà)效果
      • 參數(shù)exitAnim表示的是從Activity a跳轉(zhuǎn)到Activity b捏膨,離開(kāi)a時(shí)的動(dòng)過(guò)效果
      • 若進(jìn)入b或者是離開(kāi)a時(shí)不需要?jiǎng)赢?huà)效果,則可以傳值為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的切換動(dòng)畫(huà)

  • 6.1 定義包含動(dòng)畫(huà)的 Activity 主題
    • 在res/values/styles.xml文件中
<style name="AnimActivityTheme"  parent="@android:style/Animation.Activity">
    <item name="android:windowAnimationStyle">@style/MyWindowAnimTheme</item>
</style>
  • 6.2 定義切換動(dòng)畫(huà) style
    • 還是res/values/styles.xml 文件中
      • activityOpenEnterAnimation // 用于設(shè)置打開(kāi)新的Activity并進(jìn)入新的Activity展示的動(dòng)畫(huà)
      • activityOpenExitAnimation // 用于設(shè)置打開(kāi)新的Activity并銷(xiāo)毀之前的Activity展示的動(dòng)畫(huà)
      • activityCloseEnterAnimation // 用于設(shè)置關(guān)閉當(dāng)前Activity進(jìn)入上一個(gè)Activity展示的動(dòng)畫(huà)
      • activityCloseExitAnimation // 用于設(shè)置關(guān)閉當(dāng)前Activity時(shí)展示的動(dòng)畫(huà)
<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 定義具體動(dòng)畫(huà)文件

    • 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 應(yīng)用到對(duì)應(yīng) Activity

    • 在清單文件中添加
<activity android:name=".MainActivity"
    android:theme="@style/AnimActivityTheme”>
  • 6.5 可能出現(xiàn)的bug
    • 6.5.1 添加動(dòng)畫(huà)后食侮,出現(xiàn)從黑屏到新activity的過(guò)度
      • 問(wèn)題:添加動(dòng)畫(huà)后号涯,出現(xiàn)從黑屏到新activity的過(guò)度。
      • 原因:沒(méi)有設(shè)置相應(yīng)的消失動(dòng)畫(huà)锯七。
      • 解決方法:設(shè)置相應(yīng)的消失動(dòng)畫(huà)链快,如果不想設(shè)置消失動(dòng)畫(huà),可以使用寫(xiě)一個(gè)假動(dòng)畫(huà)眉尸,這個(gè)動(dòng)畫(huà)是沒(méi)有任何效果域蜗,只是為了避免出現(xiàn)黑屏,運(yùn)行效果為原acticity靜止不動(dòng)噪猾,新啟動(dòng)的activity執(zhí)行進(jìn)入動(dòng)畫(huà)霉祸。
    • 6.5.2 沒(méi)有動(dòng)畫(huà),或動(dòng)畫(huà)與設(shè)置不一致
      • 問(wèn)題:沒(méi)有動(dòng)畫(huà)袱蜡,或動(dòng)畫(huà)與設(shè)置不一致
      • 原因:當(dāng)頁(yè)面切換時(shí)需要進(jìn)入和消失兩個(gè)動(dòng)畫(huà)丝蹭,當(dāng)沒(méi)有進(jìn)入動(dòng)畫(huà)時(shí),消失動(dòng)畫(huà)也不會(huì)執(zhí)行坪蚁,會(huì)執(zhí)行系統(tǒng)動(dòng)畫(huà)奔穿,如果沒(méi)有系統(tǒng)動(dòng)畫(huà)則沒(méi)有動(dòng)畫(huà)镜沽,或者某個(gè)頁(yè)面使用第一或第二種方式設(shè)置了動(dòng)畫(huà)(動(dòng)畫(huà)執(zhí)行優(yōu)先級(jí),系統(tǒng)動(dòng)畫(huà) < AppTheme < (overridePendingTransition\ActivityOptionsCompat))巫橄。
      • 解決方法:為了保證進(jìn)入和消失都有動(dòng)畫(huà)淘邻,要將動(dòng)畫(huà)主題設(shè)置到兩個(gè)Activity上。也可以將主題設(shè)置到application上湘换,這樣整個(gè)應(yīng)用都是用該切換動(dòng)畫(huà)宾舅。如果是某個(gè)頁(yè)面使用第一或第二種方式設(shè)置了動(dòng)畫(huà),那么在啟動(dòng)和退出時(shí)最好都要設(shè)置彩倚,不然會(huì)造成啟動(dòng)和退出不一致的情況筹我。

7.使用ActivityOptions切換動(dòng)畫(huà)實(shí)現(xiàn)Activity跳轉(zhuǎn)動(dòng)畫(huà)

  • 7.1 這種動(dòng)畫(huà)方式介紹
    • 上面我們講解的通過(guò)overridePendingTransition方法基本上可以滿(mǎn)足我們?nèi)粘V袑?duì)Activity跳轉(zhuǎn)動(dòng)畫(huà)的需求了,但是MD風(fēng)格出來(lái)之后帆离,overridePendingTransition這種老舊蔬蕊、生硬的方式怎么能適合我們的MD風(fēng)格的App呢?好在google在新的sdk中給我們提供了另外一種Activity的過(guò)度動(dòng)畫(huà)——ActivityOptions哥谷。并且提供了兼容包——ActivityOptionsCompat岸夯。ActivityOptionsCompat是一個(gè)靜態(tài)類(lèi),提供了相應(yīng)的Activity跳轉(zhuǎn)動(dòng)畫(huà)效果们妥,通過(guò)其可以實(shí)現(xiàn)不少炫酷的動(dòng)畫(huà)效果猜扮。
  • 7.2 代碼實(shí)現(xiàn)方式
    • 代碼詮釋
      • 傳入了ActivityOptions.makeSceneTransitionAnimation,該方法表示將Activity a平滑的切換到Activity b监婶,其還有幾個(gè)重載方法可以指定相關(guān)的View旅赢,即以View為焦點(diǎn)平滑的從Activity a切換到Activity b。
      • 這里的setFeature就是為activity的窗口設(shè)置特性惑惶,不同的特性對(duì)應(yīng)不同的布局方式煮盼,比如可以設(shè)置無(wú)toolbar模式,有toolbar模式等等带污。而這里設(shè)置的是需要過(guò)渡動(dòng)畫(huà)僵控,并且我們獲取了Android中內(nèi)置的explode動(dòng)畫(huà),并設(shè)值給了Activity的window窗口對(duì)象鱼冀,這樣當(dāng)Activity被啟動(dòng)的時(shí)候就會(huì)執(zhí)行explode所帶便的動(dòng)畫(huà)效果了报破。
    • 在startActivity頁(yè)面
Intent intent = new Intent(MainActivity.this, ThreeActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());
  • 在跳轉(zhuǎn)后的頁(yè)面
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // 設(shè)置contentFeature,可使用切換動(dòng)畫(huà)
    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之后內(nèi)置的動(dòng)畫(huà)效果通過(guò)style的方式

  • 8.1 定義動(dòng)畫(huà)文件
    • 這種方式其實(shí)就是通過(guò)style的方式展示和使用ActivityOptions過(guò)度動(dòng)畫(huà),下面是實(shí)現(xiàn)通過(guò)定義style方式定義過(guò)度動(dòng)畫(huà)的步驟:
    • res目錄下新建一個(gè)transition目錄雷绢,然后創(chuàng)建資源文件泛烙,然后使用這些系統(tǒng)自帶的過(guò)渡動(dòng)畫(huà)效果理卑,這里設(shè)置了過(guò)度時(shí)長(zhǎng)為300ms
<explode xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:duration="300" />
  • 8.2 定義切換動(dòng)畫(huà)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 執(zhí)行跳轉(zhuǎn)邏輯
/**
* 點(diǎn)擊按鈕,實(shí)現(xiàn)Activity的跳轉(zhuǎn)操作
* 通過(guò)Android5.0及以上style的方式實(shí)現(xiàn)activity的跳轉(zhuǎn)動(dòng)畫(huà)
*/
/**
* 調(diào)用ActivityOptions.makeSceneTransitionAnimation實(shí)現(xiàn)過(guò)度動(dòng)畫(huà)
*/
Intent intent = new Intent(MainActivity.this, FourActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());

9.使用ActivityOptions動(dòng)畫(huà)共享組件的方式實(shí)現(xiàn)跳轉(zhuǎn)Activity動(dòng)畫(huà)

  • 這里的共享組件動(dòng)畫(huà)效果是指將前面一個(gè)Activity的某個(gè)子View與后面一個(gè)Activity的某個(gè)子View之間有過(guò)渡效果翘紊,即在這種過(guò)度效果下實(shí)現(xiàn)Activity的跳轉(zhuǎn)操作。那么如何實(shí)現(xiàn)兩個(gè)組件View之間實(shí)現(xiàn)過(guò)渡效果呢藐唠?
  • 9.1 定義共享組件
    • 在Activity a中的button按鈕點(diǎn)擊transitionName屬性:
<Button
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:text="組件過(guò)度動(dòng)畫(huà)"
    Android:transitionName="shareNames"/>
  • 在Activity b的布局文件中為組件定義transitionName屬性帆疟,這樣這兩個(gè)組件相當(dāng)于有了過(guò)度對(duì)應(yīng)關(guān)系鹉究,這里需要注意的是這兩個(gè)組件的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 調(diào)用startActivity執(zhí)行跳轉(zhuǎn)動(dòng)畫(huà)
    • 需要說(shuō)明的是這里調(diào)用的ActivityOptions.makeSceneTransitionAnimation方法踪宠,傳遞了三個(gè)參數(shù)自赔,其中第一個(gè)參數(shù)為context對(duì)象,第二個(gè)參數(shù)為啟動(dòng)Activity的共享組件柳琢,第三個(gè)參數(shù)為啟動(dòng)Activity的共享組件transitionName屬性值绍妨。
/**
* 點(diǎn)擊按鈕,實(shí)現(xiàn)Activity的跳轉(zhuǎn)操作
* 通過(guò)Android5.0及以上共享組件的方式實(shí)現(xiàn)activity的跳轉(zhuǎn)動(dòng)畫(huà)
*/
Intent intent = new Intent(MainActivity.this, FiveActivity.class);
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, button, "shareNames").toBundle());
  • 9.3 關(guān)于這幾種方式的動(dòng)畫(huà)總結(jié)
    • 通過(guò)overridePendingTransition方式和ActivityOptions動(dòng)畫(huà)API實(shí)現(xiàn)Activity的切換動(dòng)畫(huà)效果;
    • overridePendingTransition方法從Android2.0開(kāi)始柬脸,基本上能夠覆蓋我們activity跳轉(zhuǎn)動(dòng)畫(huà)的需求他去;
    • ActivityOptions API是在Android5.0開(kāi)始的,可以實(shí)現(xiàn)一些炫酷的動(dòng)畫(huà)效果倒堕,更加符合MD風(fēng)格灾测;
    • ActivityOptions還可以實(shí)現(xiàn)兩個(gè)Activity組件之間的過(guò)度動(dòng)畫(huà);

10.其他說(shuō)明

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末垦巴,一起剝皮案震驚了整個(gè)濱河市媳搪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌骤宣,老刑警劉巖秦爆,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異涯雅,居然都是意外死亡鲜结,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)活逆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)精刷,“玉大人,你說(shuō)我怎么就攤上這事蔗候∨剩” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵锈遥,是天一觀的道長(zhǎng)纫事。 經(jīng)常有香客問(wèn)我,道長(zhǎng)所灸,這世上最難降的妖魔是什么丽惶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮爬立,結(jié)果婚禮上钾唬,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好抡秆,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布奕巍。 她就那樣靜靜地躺著,像睡著了一般儒士。 火紅的嫁衣襯著肌膚如雪的止。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,245評(píng)論 1 299
  • 那天着撩,我揣著相機(jī)與錄音诅福,去河邊找鬼。 笑死拖叙,一個(gè)胖子當(dāng)著我的面吹牛权谁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播憋沿,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼旺芽,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了辐啄?” 一聲冷哼從身側(cè)響起采章,我...
    開(kāi)封第一講書(shū)人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎壶辜,沒(méi)想到半個(gè)月后悯舟,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砸民,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年抵怎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岭参。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡反惕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出演侯,到底是詐尸還是另有隱情姿染,我是刑警寧澤,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布秒际,位于F島的核電站悬赏,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏娄徊。R本人自食惡果不足惜闽颇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望寄锐。 院中可真熱鬧兵多,春花似錦捻脖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)沿癞。三九已至援雇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間椎扬,已是汗流浹背惫搏。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蚕涤,地道東北人筐赔。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像揖铜,于是被迫代替她去往敵國(guó)和親茴丰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,090評(píng)論 25 707
  • 十年前的士兵突擊5 其實(shí)從史今班長(zhǎng)退伍的那一刻天吓,我覺(jué)得三多才真正到了內(nèi)心覺(jué)醒的時(shí)候贿肩,他才真正的割掉內(nèi)心最后一點(diǎn)依賴(lài)...
    布衣觀天下閱讀 542評(píng)論 0 2
  • 猜猜我是誰(shuí)。 教育似水龄寞,看起來(lái)是平的汰规,下起來(lái)是深的。 教育孩子物邑,家長(zhǎng)一生的事業(yè)溜哮。 現(xiàn)在的家長(zhǎng):1.自己還是孩子2....
    揚(yáng)帆起航1閱讀 231評(píng)論 0 0
  • Marva Collins’ Way茂嗓,這里是豆瓣鏈接。 看評(píng)論科阎,大部分都是看哈佛公開(kāi)課在抛,幸福課追來(lái)的。 這本書(shū)不管...
    珂粒閱讀 439評(píng)論 0 2