Andorid Transitions Framework(過渡動畫)

Material-Animaltion

英文原文 https://github.com/lgvalle/Material-Animations

這是GitHub上的一個開源項(xiàng)目(點(diǎn)擊傳送門), 演示View的平移、縮放動畫,activity進(jìn)入和退出動畫,界面間元素共享。

Andorid Transitions Framework

了解 Transition Framework

作用

  • 可以在activity之間跳轉(zhuǎn)的時候添加動畫

  • 動畫共享元素之間的轉(zhuǎn)換活動

  • activity中布局元素的過渡動畫。

1. Transitions between Activitys

  • Animate existing activity layout content
image
image

當(dāng)過渡從activity到activity內(nèi)容布局是根據(jù)定義的過渡動畫。有三個預(yù)定義的轉(zhuǎn)換android.transition上可用。轉(zhuǎn)換可以使用:Explode,Slide和Fade。所有這些轉(zhuǎn)換跟蹤更改目標(biāo)的可見性活動視圖布局和動畫那些觀點(diǎn)遵循轉(zhuǎn)換規(guī)則。

Explode Slide Fade
image
image
image
image

實(shí)現(xiàn)這些效果可以通過xml方式或者在直接在類中實(shí)現(xiàn),下面是Fade的實(shí)現(xiàn)方式。

說明:Fade

  1. 如果是xml方式實(shí)現(xiàn),首先在/res下創(chuàng)建transition文件夾。

res/transition/slide_from_right

<?xml version = 1.0 encoding = "utf-8"?>
<transitionSet xmls:android = "http://schemas.android.com/apk/res/android">

<slide duration = "500"
       slideEage = "left"/>
       
</transitionSet>

2.如果直接用代碼實(shí)現(xiàn),可以如下實(shí)現(xiàn)

MainActivity

Slide slideTracition = newSlide();

slideTracition.setSlideEdge(Gravity.LEFT);

slideTracition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
   

  1. 實(shí)現(xiàn)

MianActivity.onCreat();

設(shè)置MainActivty的進(jìn)出動畫代碼如下

  private void setupWindowAnimations() {
        Transition slideTracition = TransitionInflater.from(this).inflateTransition(R.transition.slide_from_left);
        getWindow().setEnterTransition(slideTracition);
        getWindow().setExitTransition(slideTracition);
        //getWindow().setReenterTransition(buildExitTransition());
    }
    
  1. 分析Fade的步驟是怎么發(fā)生的
    1. ActivatyA 啟動 ActivityB
    2. Transition Framework找到一個ExitTransition,并將其應(yīng)用于所有可見視圖。
    3. 在返回之前過渡框架執(zhí)行進(jìn)入和退出分別反向動畫(如果我們定義的輸出returnTransition和reenterTransition,這些都已經(jīng)轉(zhuǎn)而執(zhí)行)

ReturnTransition&ReenterTransition

返回和重新輸入轉(zhuǎn)換分別是Enter和Exit的反向動畫。

  • EnterTransition < - > ReturnTransition
  • ExitTransition < - > ReenterTransition

如果未定義返回或重新輸入,Android將按照你之前設(shè)定的默認(rèn)的版本。但是如果你定義它們,你可以有不同的轉(zhuǎn)換進(jìn)入和退出活動。(如下圖)

image
  • 當(dāng)你從ActivityB返回到ActivityA的時候。需要重新制定ActivityB的退出動畫,可以通過如下方式
Visiable slide = new Slide();
slide.setDuraing(500);
getWindow.setReturnTransition(slide);
//別直接調(diào)用finish();
finshAfterTransition();

效果圖

Without Return Transition With Return Transition
image
image
image
image

2.Share elements between Activity(元素共享)

共享元素過度動畫的背后是通過過度動畫將兩個不同布局中的不同view關(guān)聯(lián)起來。Transition框架知道用適當(dāng)?shù)膭赢嬒蛴脩粽故緩囊粋€view向另外 一個view過度。請記?。汗蚕碓剡^度的過程中,view并沒有真正從一個布局跑到另外一個布局,整個過程基本都是在后一個布局中完成的。

image
image

a) 允許過度動畫

需要在/res/style.xml添加

   <item name="android:windowContentTransitions">true</item>
   

b) 在對應(yīng)的xml文件指定TransitionName屬性

res/layout/activity

  • 指定ImageView和TextView

注意:這里必須為共享的倆個元素指定同一個TransitionName,不然不會出現(xiàn)共享效果

 <ImageView
        android:id="@+id/square_blue"
        style="@style/MaterialAnimations.Icon.Big"
        android:src="@drawable/circle_24dp"
        android:transitionName="@string/square_blue_name" />
<TextView
       android:id="@+id/title"   
       style="@style/MaterialAnimations.TextAppearance.Title.Invers"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="center_vertical|start"
       android:text="@{sharedSample.name}"
       android:transitionName="@string/sample_blue_title" />

c) 啟動Activity


Intent intent = new Intent(activity,target);
ActivityOptionCompat option = ActiviyoptionCampat.makeSceneTransitionAnimation(activity,  
new Pair<View, String>(viewHolder.binding.sampleIcon, activity.getString(R.string.square_blue_name)),
new Pair<View, String>(viewHolder.binding.sampleName, activity.getString(R.string.sample_blue_title)));

startActivity(intent,option.toBundle());

這段代碼將生成這個美麗的過渡動畫:

image

那么在Fragment之間怎么實(shí)現(xiàn)呢?

a) 允許過度動畫

需要在/res/style.xml添加

   <item name="android:windowContentTransitions">true</item>
   

b) 在對應(yīng)的xml文件指定TransitionName屬性

之前的倆個步驟和Activity之間共享元素的沒有太大差別。

c) 通過Shared Element方式啟動fragment

  private void addNextFragment(Sample sample, ImageView blue, boolean b) {
        SharedElementFragment2 elementFragment2 = SharedElementFragment2.newInstance(sample);
        Slide slide = new Slide();
        slide.setDuration(getResources().getInteger(R.integer.anim_duration_medium));
        slide.setSlideEdge(Gravity.RIGHT);
        ChangeBounds changeBounds = new ChangeBounds();
        changeBounds.setDuration(getResources().getInteger(R.integer.anim_duration_medium));
        elementFragment2.setEnterTransition(slide);
        elementFragment2.setAllowEnterTransitionOverlap(b);
        elementFragment2.setAllowReturnTransitionOverlap(b);
        elementFragment2.setSharedElementEnterTransition(changeBounds);
        getFragmentManager().beginTransaction().replace(R.id.sample2_content, elementFragment2).addToBackStack(null).addSharedElement(blue, getString(R.string.square_blue_name)).commit();
    }

效果如下

image

3.動畫視圖布局元素

上面?zhèn)z種方式都是運(yùn)用于過度動畫,那Transition FrameWork也可以被用做于改變布局中的某個特定的View,比如修改View的位置或者大小。我們需要確定想改變的結(jié)果即可。

1.我們需要告訴framework我們需要改動界面的Ui

TransitionManager.beginDelayedTransition(viewRoot);

  • 這里的viewRoot是需要改變view當(dāng)前所在的根布局

2.改變View的屬性

  • 改變大小
 ViewGroup.LayoutParams params = view.getLayoutParams();
 params.witdh = 200;
 view.setlayoutParams(params);

  • 改變位置
  ViewGroup.LayoutParams params = view.getLayoutParams();
 params.gravity = Gravity.Left;
 view.setlayoutParams(params);

Size Position
image
image

4.共享元素+循環(huán)動畫

循環(huán)顯示只是一個動畫顯示或隱藏一組UI元素。它可以自API21或以上使用。

image
image

上圖發(fā)生了幾個步驟?了解了之前的共享元素后我們知道。

  • 黃色的小球共享于MainActivity和RevealActivity。
  • 當(dāng)共享動畫結(jié)束之后,在RevealActivity中發(fā)生了倆組動畫效果
    • Toolbar上
    • 底部四個球執(zhí)行了特定的動畫

那我們應(yīng)該如何監(jiān)聽共享元素的動畫結(jié)束的時刻。

  private void setupEnterAnimations() {
        Transition transtion = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
        getWindow().setSharedElementEnterTransition(transtion);
        transtion.addListener(new Transition.TransitionListener() {
         
            @Override
            public void onTransitionEnd(Transition transition) {
                transition.removeListener(this);
                hideTarget();
                animateRevealShow(toolbar);
                animateButtonIn();
            }

           
        });
    }

res/transition/changebounds_with_arcmotion.xml

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
               android:duration="@integer/anim_duration_long"
               android:interpolator="@android:interpolator/decelerate_cubic"
    >
    <changeBounds>
        <arcMotion
            android:maximumAngle="90"
            android:minimumHorizontalAngle="90"
            android:minimumVerticalAngle="0"/>
    </changeBounds>
</transitionSet>

ToolBar Animation

private void animateRevealShow(View viewRoot) {

    int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2;
    int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2;
    int finalRadius = Math.max(viewRoot.getWidth(), viewRoot.getHeight());

    Animator anim = ViewAnimationUtils.createCircularReveal(viewRoot, cx, cy, 0, finalRadius);
    viewRoot.setVisibility(View.VISIBLE);
    anim.setDuration(1000);
    anim.setInterpolator(new AccelerateInterpolator());
    anim.start();
}

四個小球的浮現(xiàn)的動畫

private void animateButtonIn() {
        for (int i = 0; i < bgViewGroup.getChildCount(); i++) {
            View child = bgViewGroup.getChildAt(i);
            child.animate()
                    .setStartDelay(100 + i * DELAY)
                    .setInterpolator(new AccelerateInterpolator())
                    .alpha(1)
                    .scaleX(1)
                    .scaleY(1);
        }
    }

另一種效果

紅色小球的效果

image

紅球運(yùn)動軌跡 res/transition/changebounds_with_arcmotion.xml(這里不是共享動畫)

res/transition/changebounds_with_arcmotion.xml

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
               android:duration="@integer/anim_duration_long"
               android:interpolator="@android:interpolator/decelerate_cubic"
    >
    <changeBounds>
        <arcMotion
            android:maximumAngle="90"
            android:minimumHorizontalAngle="90"
            android:minimumVerticalAngle="0"/>
    </changeBounds>
</transitionSet>

點(diǎn)擊紅色小球時 執(zhí)行 revealRed()

  private void revealRed() {
        final ViewGroup.LayoutParams params = btnRed.getLayoutParams();
        Transition transition = TransitionInflater.from(this).inflateTransition(R.transition.changebounds_with_arcmotion);
        transition.addListener(new Transition.TransitionListener() {
            @Override
            public void onTransitionStart(Transition transition) {

            }

            @Override
            public void onTransitionEnd(Transition transition) {
                animateRevealColor(bgViewGroup, R.color.sample_red);
                body.setText(R.string.reveal_body3);
                body.setTextColor(ContextCompat.getColor(RevealActivity.this, R.color.theme_red_background));
                btnRed.setLayoutParams(params);
            }

            @Override
            public void onTransitionCancel(Transition transition) {

            }

            @Override
            public void onTransitionPause(Transition transition) {

            }

            @Override
            public void onTransitionResume(Transition transition) {

            }
        });
        TransitionManager.beginDelayedTransition(bgViewGroup, transition);
        final RelativeLayout.LayoutParams relativeRarams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        relativeRarams.addRule(RelativeLayout.CENTER_IN_PARENT);
        btnRed.setLayoutParams(relativeRarams);
    }
    
    
    
    private void animateRevealColor(ViewGroup viewRoot, @ColorRes int color) {
        int cx = (viewRoot.getLeft() + viewRoot.getRight()) / 2;
        int cy = (viewRoot.getTop() + viewRoot.getBottom()) / 2;
        animateRevealColorFromCoordinates(viewRoot, color, cx, cy);
    }
    
    
    
     private Animator animateRevealColorFromCoordinates(ViewGroup root, @ColorRes int color, int cx, int cy) {
        int finalRadius = Math.max(root.getWidth(), root.getHeight());
        final Animator animator = ViewAnimationUtils.createCircularReveal(root, cx, cy, 0, finalRadius);
        root.setBackgroundColor(ContextCompat.getColor(this, color));
        animator.setDuration(getResources().getInteger(R.integer.anim_duration_long));
        animator.setInterpolator(new AccelerateInterpolator());
        animator.start();
        return animator;
    }

更多信息

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容