Android使用CircularReveal動畫效果切換頁面

zc1969 8年前發布 | 41K 次閱讀 Android開發 移動開發

來自: http://blog.csdn.net/caroline_wendy/article/details/50756717


本文地址: http://blog.csdn.net/caroline_wendy/article/details/50756717

歡迎Follow我的GitHub, 關注我的CSDN.

Android的Material Design設計理念, 帶來很多絢麗的動畫效果. 在頁面切換中, 最常用的就是SharedElementTransition, 通過設置控件的變換方式, 在進入時把控件變換為頁面, 在退出時, 把頁面變換為控件, 同時, 可以設置控件移動的軌跡. 這樣的控件, 可以應用于消息通知, 或者廣告顯示, 提供非常好的用戶體驗. 那么是如何實現的呢?

Material Design

隨著廠商的版本迭代, 超過三分之一的手機都是5.0以上的操作系統, 隨著更多便宜的低端手機普及5.0+系統(如紅米系列), 給用戶帶來更好的體驗, 會大大增加應用留存率.

Android系統(20160227)

本文主要內容:
(1) 修改分享元素的滑動軌跡, 以90°圓弧方式出現和返回, 即transition動畫.
(2) 生成和銷毀頁面的爆炸和凝聚效果, 即CircularReveal的使用方式.

本文源碼的GitHub下載地址.

最終動畫效果
CircularReveal


1. 首頁

新建一個含義Fab按鈕的HelloWorld工程. 添加ButterKnife和Lambda庫.

設置Fab按鈕的跳轉事件.

    // Fab的跳轉事件
    public void startOtherActivity(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            ActivityOptions options =
                    ActivityOptions.makeSceneTransitionAnimation(this, mFab, mFab.getTransitionName());
            startActivity(new Intent(this, OtherActivity.class), options.toBundle());
        } else {
            startActivity(new Intent(this, OtherActivity.class));
        }
    }

確保版本號大于5.0, 支持Material Design的動畫效果.

</blockquote>

設置Fab的TransitionName, 即變化名稱.

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:clickable="true"
        android:onClick="startOtherActivity"
        android:src="@android:drawable/ic_dialog_email"
        android:transitionName="@string/other_transition_name"
        tools:targetApi="lollipop"/>

注意android:transitionName屬性, 表示變換名稱.

</blockquote>


2. 跳轉頁

頁面由背景, 變化控件, 關閉控件, 這三部分組成.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout  android:id="@+id/other_rl_container" xmlns:android="

<android.support.design.widget.FloatingActionButton  android:id="@+id/other_fab_circle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:transitionName="@string/other_transition_name" app:backgroundTint="@color/colorAccent" app:elevation="0dp" app:fabSize="normal" app:pressedTranslationZ="8dp" tools:targetApi="21"/>

<TextView  android:id="@+id/other_tv_container" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorAccent" android:gravity="center" android:text="@string/other_text" android:textColor="@android:color/white" android:textSize="40sp" android:textStyle="bold" android:visibility="invisible" tools:visibility="visible"/>

<ImageView  android:id="@+id/other_iv_close" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" android:contentDescription="@null" android:onClick="backActivity" android:src="@drawable/ic_close_white" android:visibility="invisible"/>

</RelativeLayout></pre>

注意, 變換控件FloatingActionButton與主頁的變換控件有相同的transitionName.

</blockquote>

顯示邏輯, 設置入場和退場動畫, 爆炸的動畫效果.

    @Override protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);
        ButterKnife.bind(this);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        setupEnterAnimation(); // 入場動畫
        setupExitAnimation(); // 退場動畫
    } else {
        initViews();
    }
}</pre> 

退出邏輯, 退出動畫, 凝聚的動畫效果.

    // 退出按鈕
    public void backActivity(View view) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            onBackPressed();
        } else {
            defaultBackPressed();
        }
    }

下面仔細分析顯示和退場動畫.


3. 顯示動畫

分享元素切換使用弧度規矩, 即arc_motion, 90°旋轉過去和回來. 在動畫結束后, 頁面顯示使用爆炸效果.

    // 入場動畫
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void setupEnterAnimation() {
        Transition transition = TransitionInflater.from(this)
                .inflateTransition(R.transition.arc_motion);
        getWindow().setSharedElementEnterTransition(transition);
        transition.addListener(new Transition.TransitionListener() {
            @Override public void onTransitionStart(Transition transition) {

        }

        @Override public void onTransitionEnd(Transition transition) {
            transition.removeListener(this);
            animateRevealShow();
        }

        @Override public void onTransitionCancel(Transition transition) {

        }

        @Override public void onTransitionPause(Transition transition) {

        }

        @Override public void onTransitionResume(Transition transition) {

        }
    });
}

// 動畫展示
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void animateRevealShow() {
    GuiUtils.animateRevealShow(
            this, mRlContainer,
            mFabCircle.getWidth() / 2, R.color.colorAccent,
            new GuiUtils.OnRevealAnimationListener() {
                @Override public void onRevealHide() {

                }

                @Override public void onRevealShow() {
                    initViews();
                }
            });
}</pre> 

arc_motion角度變換

<transitionSet  xmlns:android="

<changeBounds>
    <!--suppress AndroidElementNotAllowed -->
    <arcMotion  android:maximumAngle="90" android:minimumHorizontalAngle="90" android:minimumVerticalAngle="0"/>
</changeBounds>

</transitionSet></pre>

爆炸的動畫效果

    // 圓圈爆炸效果顯示
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public static void animateRevealShow(
            final Context context, final View view,
            final int startRadius, @ColorRes int color,
            OnRevealAnimationListener listener) {
        int cx = (view.getLeft() + view.getRight()) / 2;
        int cy = (view.getTop() + view.getBottom()) / 2;

    float finalRadius = (float) Math.hypot(view.getWidth(), view.getHeight());

    // 設置圓形顯示動畫
    Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, startRadius, finalRadius);
    anim.setDuration(300);
    anim.setInterpolator(new AccelerateDecelerateInterpolator());
    anim.addListener(new AnimatorListenerAdapter() {
        @Override public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            view.setVisibility(View.VISIBLE);
            listener.onRevealShow();
        }

        @Override public void onAnimationStart(Animator animation) {
            super.onAnimationStart(animation);
            view.setBackgroundColor(ContextCompat.getColor(context, color));
        }
    });

    anim.start();
}</pre> 

使用CircularReveal, 即圓形顯示的動畫效果.
第一個參數是顯示的視圖, 第二個和第三個是變換的中心位置, 第三個和第四個是變換的起始半徑和結束半徑.


4. 退出動畫

退出動畫是凝聚效果, 同樣使用的是CircularReveal.

    // 退出事件
    @Override public void onBackPressed() {
        GuiUtils.animateRevealHide(
                this, mRlContainer,
                mFabCircle.getWidth() / 2, R.color.colorAccent,
                new GuiUtils.OnRevealAnimationListener() {
                    @Override
                    public void onRevealHide() {
                        defaultBackPressed();
                    }

                @Override
                public void onRevealShow() {

                }
            });
}</pre> 

退出和顯示的區別就是起始和終止的半徑不同.

    // 圓圈凝聚效果
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public static void animateRevealHide(
            final Context context, final View view,
            final int finalRadius, @ColorRes int color,
            OnRevealAnimationListener listener
    ) {
        int cx = (view.getLeft() + view.getRight()) / 2;
        int cy = (view.getTop() + view.getBottom()) / 2;
        int initialRadius = view.getWidth();
        // 與入場動畫的區別就是圓圈起始和終止的半徑相反
        Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, finalRadius);
        anim.setDuration(300);
        anim.setInterpolator(new AccelerateDecelerateInterpolator());
        anim.addListener(new AnimatorListenerAdapter() {
            @Override public void onAnimationStart(Animator animation) {
                super.onAnimationStart(animation);
                view.setBackgroundColor(ContextCompat.getColor(context, color));
            }

        @Override public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            listener.onRevealHide();
            view.setVisibility(View.INVISIBLE);
        }
    });
    anim.start();
}</pre> 

最后說一些有關用戶體驗的事情, 對于一款應用而言, 好的性能固然重要, 但優秀的設計也非常關鍵, 優異的產品需要優異的展現方式.

OK, that’s all! Enjoy it!

</div>

 本文由用戶 zc1969 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!