Material-Animations-master學習筆記

Material-Animations-master 學習筆記

好久都有更新博客了,從入安卓開始,學習,上班,最近跳槽了,去了新東家那,離自己的心中的工作又進了一步,新單位同事,領導都挺好,可惜,事業上剛有起色,感情上卻受到打擊,哎,寫一篇博客安慰一下自己吧。

最近公司沒有新的業務,自己也抽空學習一些新東西,比如5.0新出的TransitionAnimation,雖然之前也接觸過,想學,不過一直沒有時間,最近學着都敲了一遍,感覺蠻不錯的,參考的項目就是Material-Animations-master,一個特別棒的介紹過渡動畫和Transition的項目。

先總體介紹下,總體分四部分,簡單的過渡動畫,分享元素的過渡動畫,通過Transition實現的view動畫,ReveaAimation四種,接下來都以此介紹一下。

簡單過渡動畫

簡單的過渡動畫分三種吧,Slide,Fade,Explode,滑動,漸變,爆炸三種,基本的使用方法

    Slide slideTransition=new Slide();
    slideTransition.setSlideEdge(Gravity.LEFT);
    slideTransition.setDuration(getResources().getInteger(R.integer.anim_duration_long));
    getWindow().setReenterTransition(slideTransition);
    getWindow().setExitTransition(slideTransition);

簡單的就是new一個Transition對象,做一些基本設置就可以了,動畫有了,接下來就是要設置到指定的位置。

    getWindow().setEnterTransition(slideTransition);//設置進入動畫
    getWindow().setExitTransition(slideTransition);//設置退出動畫
    getWindow().setReturnTransition(slideTransition);//設置返回的動畫(這個沒具體試過)
    getWindow().setReenterTransition(slideTransition);//設置重新進入的動畫

簡單的過渡動畫就這麼簡單,接下來就是使用startActivity就可以了,在項目中使用了一下別的東西,比如DataBindig,還有RecyclerView,首頁面的跳轉是通過SamplesRecyclerAdapter裏面統一處理的,封裝了兩個方法用於跳轉的不同情況。在Transition中還有一種就是使用XML去編寫Transaction,簡單的操作跟屬性動畫並無區別,新建一個transition文件夾,在裏面創建文件就可以了, 並不困難,同樣的在使用時候使用TransitonSet進行控制,也有interpolator等屬性。

transition= TransitionInflater.from(this).inflateTransition(R.transition.explode);

簡單的inflate操作,不難理解。

分享元素動畫

分享元素作爲一種非常有視覺層次感的過渡效果,是值得去追求和學習的。
先說首頁跳轉到shareFragment的分享元素吧,在adapter中設置的點擊時間具體代碼

 private void transitionToActivity(Class target,SampleViewHolder holder,Sample sample){
    final Pair<View,String>[] pairs=TransitionHelper.
            createSafeTransitionParticipants(activity,false,
                    new Pair<>(holder.binding.sampleIcon,activity.getString(R.string.square_blue_name)),
                    new Pair<>(holder.binding.sampleName,activity.getString(R.string.sample_blue_title)));
    startActivity(target,pairs,sample);
}

可以看到在使用的過程中出現了一個新的類 Pair,簡單來說就是一個容器類,跟Map,Set之類的差不多,不過在這裏使用的是View和String。用來標記被共享的元素和共享元素的name。在首頁的使用過程中是在Adapter中的,所以這種方式可以使用在一些列表或者圖片列表效果中,效果會很棒,通過TransitionHelper.createSafeTransitionParticipants方法創建一個Pair對象數組,包含這目標Activity,是否包含目標statusBar,以及兩個包含着View與String對應的Pair對象。
接下來通過

private void startActivity(Class target, Pair<View, String>[] pairs, Sample sample) {
    Intent i=new Intent(activity,target);
    ActivityOptionsCompat transitionActivityOptions=ActivityOptionsCompat.
            makeSceneTransitionAnimation(activity,pairs);
    i.putExtra("sample",sample);
    activity.startActivity(i,transitionActivityOptions.toBundle());
}

通過ActivityOptionsCompat.makeSceneTransitionAnimation方法來創建一個ActivityOptions對象,其實在5.0之前或者說在沒有分享元素,Transition的時候我們也還是可以通過這種方式來控制要啓動的actiivty的動畫的,使用之前的補間動畫就可以。這樣一個簡單的分享元素動畫就實現了, 不過在項目中,我們可以發現,其實在shareFragment中並不是一個簡單的Activity,而是包含着兩個Fragment的Activity主體內容並沒有在activity中,而且值得注意的是,在共享的兩個View 中其中一個是在Activity中另一個則是在包含的Fragment中,而在這個Fragment中沒有做一些過多的操作,僅僅是設置了一下過度元素效果,5.0中包含以下效果:

  • changeBounds 改變目標視圖的佈局邊界
  • changeClipBounds 裁剪目標視圖邊界
  • changeTransform 改變目標視圖的縮放比例和旋轉角度
  • changeImageTransform 改變目標圖片的大小和縮放比例

通過這兩點,可以發現,對於共享元素,沒有要求指定要在同一個界面中,一個在Activity一個在Fragmen,或者兩個都在Fragment中,目測只要能夠顯示都可以,必要的實在xml文件中要設置制定的屬相,transitioonName作爲別分享元素的標記,要與之前在pair中包括的View和String相對應。然後介紹下Fragment設置共享元素效果的方法。直接在開啓的事務中添加addSharedElement()這個方法,傳入View和String,當然還是要保持相同的transitionName。更多的就是有兩個方法,用來判斷是否可以讓兩個過渡動畫同時進行,感覺還是不同時進行好一點。

View animations

這個講的不是過渡動畫,就是簡單的view動畫,不過不同我們之前學習的補間或者屬性動畫,這種動畫是通過兩個不同的scene來實現的,感覺這個纔是Transition 的本質,過渡動畫和分享元素是它的延伸。scene這個單詞翻譯過來是場景,那就叫過場動畫吧,以便與過渡動畫區分一下,並沒有切換Activity或者Fragment只是換了一個場景。在android的發展過程中,隨着用戶數量的整體系統平臺的提升,越來越多或者說更加優良,有視覺衝擊的動畫被使用, 也出現了很多不同的實現動畫的形式,除了我們所熟知的幀動畫,屬性動畫,補間動畫,更多的矢量圖動畫,過場動畫將被越來越的使用。
在這個項目中使用過場動畫有兩處,一種簡單的改變位置和大小,另一種是改變場景。分別介紹一下。

位置大小

先上代碼,很好理解

    TransitionManager.beginDelayedTransition(viewRoot);
    LinearLayout.LayoutParams lp= (LinearLayout.LayoutParams) square.getLayoutParams();
    if(positionChaged){
        lp.gravity= Gravity.CENTER;
    }else {
        lp.gravity=Gravity.LEFT;
    }
    positionChaged=!positionChaged;
    square.setLayoutParams(lp);

其中viewRoot是視圖的佈局,square是要改變的view。首先會調用TransitionManager.beginDelayedTransition();方法來確定要施展動畫的佈局和Transition的類型,只添加view就是使用默認的Transition,之後就是簡單的更改佈局中的屬性或者view自身的屬性來實現動畫效果。

    TransitionManager.beginDelayedTransition(viewRoot);
    ViewGroup.LayoutParams params=square.getLayoutParams();
    if(sizeChanged){
        params.width=saveWidth;
    }else{
        saveWidth=params.width;
        params.width=200;
    }
    sizeChanged=!sizeChanged;
    square.setLayoutParams(params);

更改view大小的代碼基本類似,我們可以簡單的看一下效果,會發現,這麼寫其實和寫一個屬性動畫差不多,都是通過改變view自身來改變的,不過對於屬性動畫來說想要改變位置會主動改變自身的位置,而不是像過場動畫一下,去改變父佈局的屬性,來實現,從這一點來說,過場動畫更靈活,也適用更多的場景和複雜的動畫,我們繼續往下看。

場景變換

作爲Transition的基本使用,個人感覺過渡動畫並不是Transition的主要功能,簡單有效的從一個場景切換到另一個場景,過渡平滑不突兀,這纔是Transition應該有的操作。
這AnimationActivity2中有五個Scene,在頁面加載的時候就通過TransitionManager.go(scene0);方法來初始化一個場景並添加到Activity中,初始化時通過

    scene0=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene0,this);
    scene0.setEnterAction(new Runnable() {
        @Override
        public void run() {
            for(int i=0;i<viewsToAnimate.size();i++){
                View child=viewsToAnimate.get(i);
                child.animate()
                        .setStartDelay(i*DELAY)
                        .scaleX(1)
                        .scaleY(1);
            }
        }
    });
    scene0.setExitAction(new Runnable() {
        @Override
        public void run() {
            TransitionManager.beginDelayedTransition(activityRoot);
            View title=scene0.getSceneRoot().findViewById(R.id.scene0_title);
            title.setScaleX(0);
            title.setScaleY(0);
        }
    });

先通過getSceneForLayout方法來獲得一個Scene對象,而且可以給這個場景設置進入和退出的動作,在初始化的時候需要指定要替換的佈局。
之後繼續初始化其他四個Scene

    scene1=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene1,this);
    scene2=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene2,this);
    scene3=Scene.getSceneForLayout(sceneRoot,R.layout.activity_animations_scene3,this);
    scene4=Scene.getSceneForLayout(sceneRoot, R.layout.activity_animations_scene4,this);

在場景初始化之後就可以通過TransitionManager.go(scene1,new ChangeBounds());方法來更換場景並且可以指定切換場景間的動畫。看過項目的人都清楚,如果單純的讓我們用屬性動畫去做的話,那個工作量可不是一般的大。在複雜佈局的切換中使用這種改變場景的方式明顯的更爲方便和便捷。

RevealAnimation

RevealAnimation 中文不準確的翻譯:揭露動畫(有點不雅)。這個裏面涉及的有些多,一步步分開來說。
首先是進入的動畫,一個橘黃色的小球的共享元素動畫。這動畫的過程中,可能是本人個人水平有限,仔細觀察後發現其實移動的路徑是曲線而且退出和進入時的路徑是不同的,而且在代碼中並沒有指定移動的路徑,猜測是共享元素過程中默認設置的。有待研究。接下來就按照顏色去分析。

綠色

在點擊綠色按鈕之後會從佈局的中間偏下的位置開始一個Reveal動畫,查看調用的方法我們可以找個這個:

/**
 *創建Reveal動畫並執行
 *
 * @param viewRoot 要執行動畫的佈局
 * @param color 揭露的顏色
 * @param cx 揭露點的X座標
 * @param cy 揭露點的Y座標
 * @return 返回創建成功的動畫
 */
    private Animator animateRevealColorFromCoordinates(ViewGroup viewRoot, int color, int cx, int cy) {
    float finalRadius= (float) Math.hypot(viewRoot.getWidth(),viewRoot.getHeight());

    Animator anim=ViewAnimationUtils.createCircularReveal(viewRoot,cx,cy,0,finalRadius);
    viewRoot.setBackgroundColor(ContextCompat.getColor(this,color));
    anim.setDuration(getResources().getInteger(R.integer.anim_duration_long));
    anim.setInterpolator(new AccelerateDecelerateInterpolator());
    anim.start();
    return anim;
}

首先通過math.hypot一個沒有見過的數學方法來求出要執行的最終的半徑,hypot方法的意思是求兩個數平方和的平方根,白話的意思就是求直角三角形斜邊長。用在這裏的意思就是求佈局對角線的長度。之後通過ViewAnimationUtils.createCircularReveal()方法創建一個RevealAnimator,需要的參數有佈局,座標點,起始半徑和最終半徑。設置時間和差值器之後就可以運行了,使用並不難。

紅色

點擊紅色按鈕與點擊綠色按鈕的動畫有兩點不同,一是會有一個紅球的位移,二是在紅球右側的藍球和橘黃色球會往右有一個簡單的位移和縮小,至於揭露動畫的部分其實就是一個顏色的改變。

 final ViewGroup.LayoutParams originalParams = 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(originalParams);
        }

        @Override
        public void onTransitionCancel(Transition transition) {
        }

        @Override
        public void onTransitionPause(Transition transition) {

        }

        @Override
        public void onTransitionResume(Transition transition) {

        }
    });
    TransitionManager.beginDelayedTransition(bgViewGroup, transition);
    RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
    layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
    btnRed.setLayoutParams(layoutParams);

簡單看來就是先獲得當前的佈局狀態,之後開啓一個之前用過的Transition,設置新的佈局屬性,這個主要是用來實現紅球從底部移動到屏幕中部,之後開啓一個揭露動畫,之前介紹過就不多贅述了,比較奇怪的是在代碼中並沒有看到關於在紅球移動過程中對其他幾個球的動畫代碼,從這一點上來看,過場動畫的強大,會默認的幫我們實現一些符合現實情景的動作。

剩下的藍球和黃球其實就是改變揭露動畫的起始位置,其他的並沒有太大的變化,就說到這。

總結

關於動畫的東西其實我寫了很多,主要是個人比較喜歡這種東西,從最基礎的幀動畫,補間動畫,再到屬性動畫,多種不同方式去實現屬性動畫,再到5.0的過渡動畫和過場動畫,分享元素,更多的還有SVG矢量圖動畫等等,隨着Android系統的發展,有越來越多的形式能夠使我們的APP變得更加貼近生活,更能吸引人。我們也要不斷的學習心的東西,纔不會被時代淘汰掉。

以後可能會換個地方寫文章,爭取每週一篇,可以的話也會弄一個個人的博客,文章也會同步更新到簡書。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章