低版本實現共享元素動畫(二):格瓦拉動畫

譯文的GitHub地址:低版本實現共享元素動畫(二):格瓦拉動畫

譯者注:好久沒折騰動畫了,一開始就停不下來了

最后實現效果

剛寫完低版本實現共享元素動畫,ios的同事丟過來手機告訴我格瓦拉app的一個動畫很好看,我一看還真不錯,就問android版本的實現呢,打開他的香檳金小米5以為是和ios一樣的實現,可惜只實現了一半,盯得動畫看了一會,發現有點像是android material設計動畫,然后他又給我看了好幾個app的動畫,一看我就發現了,ios好多app動畫都是android material設計里面的,而且不少是material的錯誤示范,哈哈

像格瓦拉app這個動畫,看過google的material設計,會很熟悉,但是這個動畫 用戶等待內容的時間太長了,體驗并不是那么的好,google不推薦。先不討論對不對了,我們來簡單實現一下吧

主要步驟

主要流程其實和上一篇動畫差不多,只不過B頁面多了一個Reveal動畫,這個動畫我們用一個三方庫來實現

 compile ('com.github.ozodrukh:CircularReveal:2.0.1@aar') {
        transitive = true;
    }

我們來分析一下B頁面,可以看到有好幾層,在android中這個可以用RelativeLayout來實現

Activity B
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

    <!--layer 1-->
    <LinearLayout
        android:id="@+id/bg_detail"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:orientation="vertical">

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="160dp"
            android:background="@color/gray">
        </ImageView>
    </LinearLayout>


    <!--layer 2-->
    <io.codetail.widget.RevealFrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:id="@+id/container_detail"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/blue"
            android:orientation="vertical"
            android:visibility="invisible">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="160dp"
                android:background="@color/colorPrimary">
            </ImageView>

        </LinearLayout>
    </io.codetail.widget.RevealFrameLayout>


    <!--layer 3-->
    <ImageView
        android:id="@+id/iv_detail"
        android:layout_width="80dp"
        android:layout_height="120dp"
        android:layout_marginLeft="40dp"
        android:layout_marginTop="100dp"
        android:background="@color/colorAccent"/>

</RelativeLayout>

動畫的流程是

  1. layer 2默認不可見
  2. layer 3 共享元素移動
  3. layer 2 開始reveal動畫

也就是在上一篇的基礎上再加個動畫

  private void runEnterAnimation() {
        destinationView.setVisibility(View.VISIBLE);
        destinationView.animate()
                .setDuration(DEFAULT_DURATION)
                .setInterpolator(DEFAULT_INTERPOLATOR)
                .scaleX(1f)
                .scaleY(1f)
                .translationX(0)
                .translationY(0)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        revealOn();//添加reval動畫
                    }
                })
                .start();

    }


private void revealOn() {
    int cx = destinationView.getRight() - destinationView.getWidth() / 2;
    int cy = destinationView.getTop() + destinationView.getHeight() / 2;
    float radius = (float) Math.hypot(containerView.getWidth(), containerView.getHeight());
    Animator animator = ViewAnimationUtils.createCircularReveal(containerView, cx, cy, 0, radius);
    animator.setInterpolator(DEFAULT_INTERPOLATOR);
    animator.setDuration(900);
    animator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationStart(Animator animation) {
            containerView.setVisibility(View.VISIBLE);
        }
    });
    animator.start();
}

退出的話 以進入動畫相反順序執行

 @Override
 public void onBackPressed() {
        revealOff();
 }

public void revealOff() {
    int cx = destinationView.getRight() - destinationView.getWidth() / 2;
    int cy = destinationView.getTop() + destinationView.getHeight() / 2;
    float radius = (float) Math.hypot(containerView.getWidth(), containerView.getHeight());
    Animator animator = ViewAnimationUtils.createCircularReveal(containerView, cx, cy, radius, 0);
    animator.setInterpolator(DEFAULT_INTERPOLATOR);
    animator.setDuration(900);
    animator.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            containerView.setVisibility(View.INVISIBLE);
            runExitAnimation();
        }
    });
    animator.start();
}


private void runExitAnimation() {
    destinationView.animate()
            .setDuration(DEFAULT_DURATION)
            .setInterpolator(DEFAULT_INTERPOLATOR)
            .scaleX(scaleX)
            .scaleY(scaleY)
            .translationX(deltaX)
            .translationY(deltaY)
        /*    .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    bgView.setVisibility(View.INVISIBLE);
                    finish();
                    overridePendingTransition(0, R.anim.fade_exit);
                }
            })*/
            .withEndAction(new Runnable() {
                @Override
                public void run() {
                    bgView.setVisibility(View.INVISIBLE);
                    finish();
                    overridePendingTransition(0, R.anim.fade_exit);
                }
            })
            .start();
}

最后效果會發現

  1. activity b退出的時候效果還是不理想 這可能也是格瓦拉android不實現退出動畫的原因,我覺得這個真想實現的話,通過alpha退出是可以實現和ios一樣效果的
  2. 動畫差值器尤其重要,上面退出動畫其實控制好也可以實現 我全部用的AccelerateDecelerateInterpolator 效果很生硬
  3. RecycleView Item里面獲取在屏幕位置好像會有偏差

當然只是粗糙簡單實現一下,細節沒有去深究,效果比原版差不少,重要的是看到別人的動畫時,培養如何思考的這個過程。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容