Android轉場動畫

假設,兩個有Activity A和B

  • A啟動B: A發生exit動畫,B發生enter動畫
  • B返回A:B發生return動畫,A發生reenter動畫

1、使用overridePendingTransition

activity之間切換可以使用overridePendingTransition


overridePendingTransition

其中,在A啟動B時:

  • enterAnim:是B進入的動畫
  • exitAnim:是A退出的動畫

使用起來比較簡單,如下:

startActivity(intent);
overridePendingTransition(R.anim.bottom_top_anim, R.anim.alpha_hide);

---

finish();
overridePendingTransition(R.anim.alpha_show, R.anim.top_bottom_anim);

注意:
1、overridePendingTransition方法必須在startActivity()或者finish()方法的后面。
2、如果參數是0,表示沒有動畫

2、使用windowAnimationStyle

可以在主題(Theme)中定義windowAnimationStyle,來實現轉場動畫,如下:

<item name="android:windowAnimationStyle">@style/ActivityAnim</item>
---
<style name="ActivityAnim" parent="@android:style/Animation.Activity">
    <item name="android:activityOpenEnterAnimation">@anim/enter_anim</item>
    <item name="android:activityOpenExitAnimation">@anim/exit_anim</item>
    <item name="android:activityCloseEnterAnimation">@anim/close_enter_anim</item>
    <item name="android:activityCloseExitAnimation">@anim/close_exit_anim</item>
</style>
  • 在A啟動B時:
    activityOpenEnterAnimation:B進入的動畫
    android:activityOpenExitAnimation:A退出的動畫
  • 在B后退回A時:
    activityCloseEnterAnimation:A重新進入的動畫
    activityCloseExitAnimation:B退出的動畫

關于activityOpenEnterAnimation和windowEnterAnimation?
Activity就是一個可視的人機交互界面。 每一個Activity都有一個默認的Window,一般來講,這個Window都是全屏的,當然也有例外,比如Dialog的Window就是非全屏的。他們分別設置的是activity和window的動畫
定義Window進入和退出效果(及Window,Activity,View的理解)

@anim/enter_anim

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:duration="500"
        android:fromXDelta="100%p"
        android:toXDelta="0%p"/>
</set>

---

@anim/exit_anim

<translate android:duration="500"
    android:fromXDelta="0%p"
    android:toXDelta="-100%p"/>

---

@anim/close_enter_anim

<translate android:duration="500"
    android:fromXDelta="-100%p"
    android:toXDelta="0%p"/>

---

@anim/close_exit_anim

<translate android:duration="500"
    android:fromXDelta="0%p"
    android:toXDelta="100%p"/>  

注意:
1、windowAnimationStyle需要繼承的Animation.Activity,不然一些動畫效果就沒有了
2、 以上方法(12)設置的動畫只能針對頁面中的所有元素

轉場動畫

3、內容變換(Content Transition)

content transition決定了非共享view元素,在activity和fragment切換期間是如何進入或者退出場景的(通過改變transitioning view的visibility實現)。在5.0之后content transition可以通過調用如下代碼來設置:

  • setExitTransition() :A中的View退出場景的transition
  • setEnterTransition() :使B中的View進入場景的transition
  • setReturnTransition() - 當B 返回 A時,使B中的View退出場景的transition
  • setReenterTransition() - 當B 返回 A時,使A中的View進入場景的transition

也可以在theme中定義如下style:
android:windowExitTransition、android:windowEnterTransition、android:windowReturnTransition、android:windowReenterTransition

1、Content Transition內部揭秘
在Content transition動畫(a)創建之前,framework必須通過設置transitioning view的visibility將動畫需要的狀態信息告訴a。具體來說,當Activity A啟動B之時,發生了如下的事件:
一、Activity A 調用startActivity().
1.framework遍歷A的View樹,確定當A的exit transition運行時哪些view會退出場景(即哪些view是transitioning view)。
2.A的exit transition捕獲A中transitioning view的開始狀態。
3.framework將A中所有的transitioning view設置為INVISIBLE。
4.A的exit transition捕獲到A中transitioning view的結束狀態。
5.A的exit transition比較每個transitioning view的開始和結束狀態,然后根據前后狀態的區別創建一個Animator。Animator開始運行,同時transitioning view退出場景。
二、Activity B啟動.
1.framework遍歷B的View樹,確定當B的enter transition運行時哪些view會進入場景,transitioning view會被初始化為INVISIBLE。
2.B的enter transition捕獲B中transitioning view的開始狀態。
3.framework將B中所有的transitioning view設置為VISIBLE。
4.B的enter transition捕獲到B中transitioning view的結束狀態。
5.B的enter transition比較每個transitioning view的開始和結束狀態,然后根據前后狀態的區別創建一個Animator。Animator開始運行,同時transitioning view進入場景。

通過在每個transitioning view中來回切換INVISIBLE 和VISIBLE,framework確保content transition得到創建animation(期望的animation)所需的狀態信息。顯然content Transition對象需要在開始和結束場景中都能記錄到transitioning view的visibility。 非常幸運的是抽象類Visibility已經為你做了這些工作:Visibility的子類只需要實現onAppear()onDisappear() 兩個工廠方法,在這兩個工廠方法中創建并返回一個進入或者退出場景的Animator對象。在api 21中,有三個現成的Visibility的實現:Fade, Slide, 和 Explode,他們都可以用在Activity 和 Fragment中創建content transition。如果必要,還可以自定義Visibility

來自于:深入理解Content Transition

2、怎么使用Content Transition

1、開啟內容過渡效果

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

還可以設置是否覆蓋執行,即是否同步執行還是順序執行

    <!--A退出的動畫和B進入的動畫同步進行-->
    <item name="android:windowAllowEnterTransitionOverlap">true</item>
    <!--B返回的動畫和A重新進入的動畫同步進行-->
    <item name="android:windowAllowReturnTransitionOverlap">true</item>

同樣,也有對應的setWindowAllowEnterTransitionOverlap() 、setWindowAllowReturnTransitionOverlap()方法。


windowAllowReturnTransitionOverlap=true,同步進行.gif

默認情況下,material主題的應用中enter/return的content transition會在exit/reenter的content transitions結束之前開始播放(只是稍微早于),這樣會看起來更加連貫???

2、啟動activity B

    ActivityOptionsCompat optionsCompat=ActivityOptionsCompat.makeSceneTransitionAnimation(this);
    ActivityCompat.startActivity(this, intent, optionsCompat.toBundle());

3、在B中使用內容變換

        Slide slide=new Slide(Gravity.BOTTOM);
        slide.setDuration(500);
        //內容變換,不包括底部導航欄和狀態欄
        slide.excludeTarget(android.R.id.navigationBarBackground, true);
        slide.excludeTarget(android.R.id.statusBarBackground, true);
        slide.excludeTarget(R.id.appBarLayout, true);
        getWindow().setEnterTransition(slide);
        getWindow().setReturnTransition(slide);

也可以在xml文件設置transition,使用TransitionInflater得到Transition,如下:

Transition slide=TransitionInflater.from(this).inflateTransition(R.transition.slide_anim);
slide.setDuration(500);
slide.excludeTarget(R.id.appBarLayout, true);
getWindow().setEnterTransition(slide);
getWindow().setReturnTransition(slide);

也可以直接在style中設置動畫


    <item name="android:windowExitTransition">@transition/slide_anim</item>
    <item name="android:windowEnterTransition">@transition/slide_anim</item>

其中@transition/slide_anim如下:



<!-- @transition/slide_anim-->

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <!--頂部的狀態欄以及底部的導航欄不執行動畫-->
    <targets>
        <target android:excludeId="@android:id/statusBarBackground"/>
        <target android:excludeId="@android:id/navigationBarBackground"/>
    </targets>

    <slide android:slideEdge="bottom"
        android:duration="1300"/>

    <!--<fade />-->
</transitionSet>

4、退出時調用finishAfterTransition()

內容變換

注意:
1、Material主題默認會將exit的transition設置成null,enter的transition設置成Fade 。
2、如果reenter 或者 return transition沒有明確設置,則將用exit 和enter的共享元素transition替代
4、在定義style時,對content transition使用的是android:windowEnterTransition,以前使用的是android:activityOpenEnterAnimation

3、自定義Visibility
繼承Visibility,覆蓋兩個方法:

  • onAppear() :創建并返回一個進入場景的Animator對象。
  • onDisappear():創建并返回一個退出場景的Animator對象。

public class FABTransition extends Visibility {

    private View fab;
    private Context context;
    private static final String BOTTOM_TRANSITION_Y = "FABTransition:change_transY:transitionY";


    public FABTransition(View fab, Context context) {
        this.fab = fab;
        this.context = context;
    }

    /**
     * 收集動畫的開始信息
     * @param transitionValues 只有兩個成員變量view和values, view指的是我們要從哪個view上收集信息, values是用來存放我們收集到的信息的
     *                         比如: 在captureStartValues里, transitionValues.view指的就是我們在開始動畫的界面上的那個view,
     *                         在captureEndValues指的就是在目標界面上的那個view
     */
    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        super.captureStartValues(transitionValues);
        int transY= (int) (context.getResources().getDisplayMetrics().density*56*2);
        transitionValues.values.put(BOTTOM_TRANSITION_Y,transY);

    }

    /**
     * 收集動畫結束的信息
     */
    @Override
    public void captureEndValues(TransitionValues transitionValues) {
        super.captureEndValues(transitionValues);
        transitionValues.values.put(BOTTOM_TRANSITION_Y, 0);
    }

    /**
     * 創建一個Animator
     */
    @Override
    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
        return super.createAnimator(sceneRoot, startValues, endValues);
    }

    @Override
    public Animator onAppear(ViewGroup sceneRoot, final View view, TransitionValues startValues, TransitionValues endValues) {
        if (null == startValues || null == endValues) {
            return null;
        }
        int startY= (int) startValues.values.get(BOTTOM_TRANSITION_Y);
        int endY= (int) endValues.values.get(BOTTOM_TRANSITION_Y);
        if(view==fab && startY!=endY){
            ValueAnimator valueAnimator=ValueAnimator.ofInt(startY,endY);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Object transY= animation.getAnimatedValue();
                    if(transY!=null){
                        view.setTranslationY((Integer) transY);
                    }

                }
            });
            return valueAnimator;
        }
        return null;
    }

    @Override
    public Animator onDisappear(ViewGroup sceneRoot, final View view, TransitionValues startValues, TransitionValues endValues) {
        if (null == startValues || null == endValues) {
            return null;
        }
        int startY= (int) endValues.values.get(BOTTOM_TRANSITION_Y);
        int endY= (int) startValues.values.get(BOTTOM_TRANSITION_Y);
        if(view==fab && startY!=endY){
            ValueAnimator valueAnimator=ValueAnimator.ofInt(startY,endY);
            valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Object transY= animation.getAnimatedValue();
                    if(transY!=null){
                        view.setTranslationY((Integer) transY);
                    }

                }
            });
            return valueAnimator;
        }

        return null;
    }
}

使用自定義的FABTransition ,為它添加一個Target:

        TransitionSet cotentTransition=new TransitionSet();
        Slide slide=new Slide(Gravity.LEFT);
        slide.setDuration(500);
        slide.excludeTarget(android.R.id.navigationBarBackground, true);
        slide.excludeTarget(android.R.id.statusBarBackground, true);
        slide.excludeTarget(R.id.appBarLayout, true);
        slide.excludeTarget(R.id.fab, true);
        cotentTransition.addTransition(slide);
        //fab進入動畫
        FABTransition fabTransition=new FABTransition(fab,this);
        fabTransition.addTarget(R.id.fab);
        fabTransition.setDuration(500);
        cotentTransition.addTransition(fabTransition);
        getWindow().setEnterTransition(cotentTransition);

自定義Vilibiliyy fab

4、 共享元素動畫

定義共享的view元素從一個Activity/Fragment 到另一個Activity/Fragment t是如何變化的。共享元素在進入和返回時的變換效果,可以通過window和Fragment的如下方法來設置:

  • 進入:
    setSharedElementEnterTransition()
    設置在B進入時播放的動畫,共享元素以A中的位置作為起始,B中的位置為結束來播放動畫。
  • 返回:
    setSharedElementReturnTransition()
    設置在B返回A時的動畫,共享元素以B中的位置作為起始,A中的位置為結束來播放動畫。

1、共享元素變換揭秘
我們知道,一個變換(Transition )主要有兩方面的職責:

  • 捕獲view開始和結束狀態
  • 創建一能在兩個狀態間漸變的動畫。

共享元素變換沒有什么不同。在共享元素變換開始之前,必須首先捕獲每個共享元素的開始和結束狀態(調用activity以及被調用activity中的位置、大小、外觀),有了這些信息才能決定每個共享元素的入場動畫。

framework的共享元素變換是通過運行時改變其屬性實現的,當Activity A 調用 Activity B ,發生的事件流如下:

  • Activity A調用startActivity(), Activity B被創建,測量,同時初始化為半透明的窗口和透明的背景顏色。
  • framework重新分配每個共享元素在B中的位置與大小,使其跟A中一模一樣。之后,B的進入變換(enter transition)捕獲到共享元素在B中的初始狀態。
  • framework重新分配每個共享元素在B中的位置與大小,使其跟B中的最終狀態一致。之后,B的進入變換(enter transition)捕獲到共享元素在B中的結束狀態。
  • B的進入變換(enter transition)比較共享元素的初始和結束狀態,同時基于前后狀態的區別創建一個Animator(屬性動畫對象)。
  • framework 命令A隱藏其共享元素,動畫開始運行。隨著動畫的進行,framework 逐漸將B的activity窗口顯示出來,當動畫完成,B的窗口才完全可見。

與內容變換(content transition)取決于view的可見性不同(visibility),共享元素變換取決于每個共享元素的位置、大小以及外觀。在api 21中,框架層提供了幾個Transition 的實現,可以用于定義共享元素在場景中的切換效果。
ChangeBounds -捕獲共享元素的layout bound,然后播放layout bound變化動畫。ChangeBounds 是共享元素變換中用的最多的,因為前后兩個activity中共享元素的大小和位置一般都是不同的。
ChangeTransform - 捕獲共享元素的縮放(scale)與旋轉(rotation)屬性 ,然后播放縮放(scale)與旋轉(rotation)屬性變化動畫。
ChangeClipBounds - 捕獲共享元素clip bounds,然后播放clip bounds變化動畫。
ChangeImageTransform - 捕獲共享元素(ImageView)的transform matrices 屬性,然后播放ImageViewtransform matrices 屬性變化動畫。與ChangeBounds相結合,這個變換可以讓ImageView在動畫中高效實現大小,形狀或者ImageView.ScaleType 屬性平滑過度。
@android:transition/move - 將上述所有變換同時進行的一個TransitionSet 。就如在第一章中所講的一樣,如果共享元素的進入和返回變換沒有特別聲明,框架將使用它作為默認的變換。

我們可以看到,共享元素變換并不是真正實現了兩個activity或者Fragment之間元素的共享,實際上我們看到的幾乎所有變換效果中(不管是B進入還是B返回A),共享元素都是在B中繪制出來的。Framework沒有真正試圖將A中的某個元素傳遞給B,而是采用了不同的方法來達到相同的視覺效果。A傳遞給B的是共享元素的狀態信息。B利用這些信息來初始化共享View元素,讓它們的位置、大小、外觀與在A中的時候完全一致。當變換開始的時候,B中除了共享元素之外,所有的其他元素都是不可見的。隨著動畫的進行,framework 逐漸將B的activity窗口顯示出來,當動畫完成,B的窗口才完全可見。

來自于 深入理解共享元素變換(Shared Element Transition)

2、怎么使用共享元素動畫

1、開啟內容過渡效果

2、在activity A和activity B中,為需要共享的元素設置transitionName

android:transitionName="imageView"

或者

ViewCompat.setTransitionName(view,"imageView");

3、啟動activity B

ActivityOptionsCompat options=ActivityOptionsCompat.makeSceneTransitionAnimation(this,view,ViewCompat.getTransitionName(view));
ActivityCompat.startActivity(this, intent, options.toBundle());

4、在B中設置共享元素動畫

        TransitionSet transitionSet=new TransitionSet();
        
        //改變view的位置
        ChangePositionTransition changePositionTransition=new ChangePositionTransition();
        ColorTransition colorTransition=new ColorTransition(getResources().getColor(R.color.colorPrimary), getResources().getColor(R.color.colorAccent));
        //view做RevealTransition
        CircleShareElemEnterTransition shareElemEnterRevealTransition=new CircleShareElemEnterTransition(rightTop);

        transitionSet.addTransition(shareElemEnterRevealTransition);
        transitionSet.addTransition(colorTransition);
        transitionSet.addTransition(changePositionTransition);

        transitionSet.addTarget(R.id.rightTop);
        transitionSet.setDuration(500);
        getWindow().setSharedElementEnterTransition(transitionSet);
共享元素 動畫

3、自定義Transition
繼承Transition,重新以下方法:

  • void captureStartValues(TransitionValues transitionValues):收集動畫的開始信息
    transitionValues:有兩個成員變量view和values, transitionValues.view指的就是我們在開始動畫的界面上的那個view,是從這個view上收集開始信息的, values是用來存放我們收集到的信息的
  • void captureEndValues(TransitionValues transitionValues):收集動畫結束的信息
    transitionValues.view:在結束動畫的界面上的那個view,是從這個view上收集結束信息的, transitionValues.values是用來存放收集到的信息的
  • Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) :創建一個Animator

例子如下:


public class ColorTransition extends Transition {

    private static final String COLOR_BACKGROUND = "ColorTransition:change_color:background";
    private int mStartColor;
    private int mEndColor;

    public ColorTransition(int mStartColor, int mEndColor) {
        this.mStartColor = mStartColor;
        this.mEndColor = mEndColor;
    }

    @Override
    public void captureStartValues(TransitionValues transitionValues) {
        transitionValues.values.put(COLOR_BACKGROUND,mStartColor);
    }

    @Override
    public void captureEndValues(TransitionValues transitionValues) {
        transitionValues.values.put(COLOR_BACKGROUND,mEndColor);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
        if (null == startValues || null == endValues) {
            return null;
        }

        final View view = endValues.view;

        int startColor = (int) startValues.values.get(COLOR_BACKGROUND);
        int endColor = (int) endValues.values.get(COLOR_BACKGROUND);

        if (startColor != endColor) {
            ValueAnimator animator = ValueAnimator.ofArgb(startColor, endColor);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Object value = animation.getAnimatedValue();
                    if (null != value) {
                        view.setBackgroundColor((Integer) value);
                    }
                }
            });
            return animator;
        }
        return null;
    }
}

4、有時候為了實現一些特殊的效果,需要將activity默認的背景色設置為透明

    <style name="TranslucentBg" parent="AppTheme.NoActionBar">
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>
Activity B(藍色)的style如上

5、使用SharedElementCallback
監控共享元素動畫,在共享元素進入和退出的時候都會回調,調用方法如下:

setEnterSharedElementCallback(SharedElementCallback)

常用的方法如下:

  • onMapSharedElements:裝載共享元素
  • onSharedElementStart :共享元素開始時候回調,一般是進入的時候使用
  • onSharedElementEnd :共享元素結束的時候回調,一般是退出的時候使用

一般系統會幫我們默認實現,但是,當從activity B中返回的view不是進入activity B的共享元素時,需要手動實現 ,如下圖效果


共享元素

1、在activity A中調用SharedElementCallback,

ActivityCompat.setExitSharedElementCallback(MainActivity.this,sharedElementCallback);

在onMapSharedElements重新封裝SharedElement(從activity B中返回的兩個view不同)


    private SharedElementCallback sharedElementCallback=new SharedElementCallback() {
        @Override
        public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
             //mTmpReenterState!=null,是reenter的時候調用的;mTmpReenterState==null,是exit的時候調用的
            if(mTmpReenterState!=null){
                int startingPosition = mTmpReenterState.getInt(EXTRA_STARTING_ALBUM_POSITION);
                int currentPosition = mTmpReenterState.getInt(EXTRA_CURRENT_ALBUM_POSITION);
                if (startingPosition != currentPosition) {
                    // If startingPosition != currentPosition the user must have swiped to a
                    // different page in the DetailsActivity. We must update the shared element
                    // so that the correct one falls into place.
                    String newTransitionName = data.get(currentPosition);
                    View newSharedElement = recyclerView.findViewWithTag(newTransitionName);
                    if (newSharedElement != null) {
                        names.clear();
                        names.add(newTransitionName);
                        sharedElements.clear();
                        sharedElements.put(newTransitionName, newSharedElement);
                    }
                }
                mTmpReenterState = null;
            }
        }
    };

2、在activity B中調用SharedElementCallback

ActivityCompat.setEnterSharedElementCallback(BigImgGalleryActivity.this,callback);

如果退出時的共享元素view和進入時的不一致,重新裝載sharedElement,返回

    private SharedElementCallback callback=new SharedElementCallback() {
        @Override
        public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
            BigImgFragment fragment=adapter.getCurrentFragment();
            ImageView sharedElement =fragment.getAlbumImage();
            if(startPosition!=currentPosition){
                names.clear();
                sharedElements.clear();
                String name=ViewCompat.getTransitionName(sharedElement);
                names.add(name);
                sharedElements.put(name,sharedElement);
            }
        }
    };

3、在activity B中返回進入、退出位置

    @Override
    public void finishAfterTransition() {
        Intent data = new Intent();
        data.putExtra(EXTRA_STARTING_ALBUM_POSITION, startPosition);
        data.putExtra(EXTRA_CURRENT_ALBUM_POSITION, currentPosition);
        setResult(RESULT_OK, data);
        super.finishAfterTransition();
    }

4、接受從B中返回的數據

    @Override
    public void onActivityReenter(int resultCode, Intent data) {
        super.onActivityReenter(resultCode, data);
        mTmpReenterState=data.getExtras();
        ...
    }

6、 SharedElementCallback和TransitionListener
為共享元素動畫同時添加了SharedElementCallback和TransitionListener,執行順序如下圖, 可以在共享元素動畫結束后,在TransitionListener里做一些其他的操作。比如上圖中,對于共享元素view,在加載大圖之前,我先去加載了一張小圖,在共享元素動畫執行完畢后,在去顯示大圖...

        ActivityCompat.setEnterSharedElementCallback(BigImgGalleryActivity.this,callback);
  
        Transition transition=getWindow().getSharedElementEnterTransition();
        transition.addListener(new SimpleTransitionListener() {
            @Override
            public void onTransitionStart(Transition transition) {
                Log.e("TransitionListener","onTransitionStart");
            }
        });
        
SharedElementCallback和TransitionListener

7、實現共享元素
可以將需要傳遞的數據信息(如圖片的url和bitmap的映射)封裝在一個靜態的類中,在詳情頁根據url取bitmap。如,在列表頁,添加map,在詳情頁,根據可以顯示bitmap。但是不要忘記clear。

public class ShareImgMap {
    private static Map<String,SoftReference<Bitmap>> map=new HashMap<>();
    public static  void addImg(String key,Bitmap bitmap){
        if (!bitmap.isRecycled()){
            SoftReference<Bitmap> softReference=new SoftReference<Bitmap>(bitmap);
            map.put(key,softReference);
        }
    }
    public static Bitmap getImg(String key){
        if(map.get(key)==null){
            return null;
        }
        Bitmap bitmap=map.get(key).get();
        if(bitmap==null || bitmap.isRecycled()){
            return null;
        }
        return bitmap;
    }
    public static  void  clear(){
        map.clear();
    }
}

參考:Activity之間傳遞大數據問題

8、還有好多問題不理解???
比如,怎么定義一個共享元素view,從圓形到方形的Transition(不用CircularReveal,希望的效果是圓形->圓角矩形->方形的Transition)?。。。

以后再說吧。。。

參考:
Android 過渡(Transition)動畫解析之基礎篇深入理解Android L新特性之 頁面內容&共享元素過渡動畫深入理解共享元素變換(Shared Element Transition)深入理解Content Transition ...

參考:
https://material.google.com/motion/material-motion.html#
http://www.lxweimin.com/p/98f2ec280945
http://wiki.jikexueyuan.com/project/android-training-geek/animations.html
https://developer.android.com/reference/android/transition/Transition.html
Android的Activity屏幕切換動畫(一)-左右滑動切換
利用Theme自定義Activity間的切換動畫

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

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,288評論 25 708
  • 一款好的app沒有動畫是肯定不行的(尼古拉斯.趙四) 今天在寫了個Demo的加了一下轉場動畫,效果如下: 此Dem...
    kongjn閱讀 6,225評論 2 9
  • 最近在UI中國看見一個很好看的效果,它是這樣的: 然后我上網搜了一下,發現Android5.0以上版本,在Acti...
    陳添閱讀 1,788評論 3 14
  • 單身21年,在大學的最后階段居然脫單了,“黃昏戀”的感覺很是美好,也不負自己單身這么多年。 1 男朋友是個特別外向...
    Hey你好啊閱讀 833評論 0 0
  • 智能鼠大鬧鼠國 21世紀中葉,老鼠成災,科學家發明了一批智能鼠,專門對付躲在地洞中的老鼠。其中一只智能鼠叫“三眼金...
    戎梁閱讀 400評論 0 2