MaterialDesign系列文章(三)過渡動畫的實現

你們好!wo又來了。。。幾天不見甚是想念!!!最近因爲比較忙,請原諒個人懶惰!!!寫關於MaterialDesign的文章已經有好幾篇了。昨天無心間看見了一個關於過分動畫的概念,因此今天想和你們分享一下關於過分動畫的實戰!這裏嘮叨一下,網上不少文章都是針對於頁面跳轉的動畫,其實過渡動畫不光能夠實現頁面跳轉,對一些控件也是能夠生效的。android

若是你想直接案例解析的話,能夠直接從第三條開始看!!!git

先簡單看一下效果:github

過分動畫的效果圖

本文知識點:

  • 過渡動畫的介紹:
  • 過渡動畫類的介紹:
  • 過渡動畫的按鈕分析:

過分動畫的介紹

關於過分動畫,是在Android5.0中提出的。它經過運動和切換不一樣狀態之間的元素來產生各類動畫效果。開始的時候,沒有對低版本進行適配,github上有位大神進行了相應的適相似配(使用方式) 地址以下,後來在support包中添加了對低版本的適配,因此使用的時候要注意,不然會出現警告的。。。bash

大致的繼承關係以下:markdown

  • TransitionManager
  • Transition
    • Visibility
      • Explode
      • Slide
      • Fade
    • ChangeBounds
    • TransitionSet
    • TextScale
    • ChangeClipBounds
    • ChangeImageTransform
    • ChangeScroll
    • ChangeTransform

過分動畫類的介紹:

1.TransitionManager 過分動畫管理類

這個動畫管理類,主要協調相應的動畫管理。重要的API有如下幾個:app

  • TransitionManager.beginDelayedTransition(@NonNull final ViewGroup sceneRoot, @Nullable Transition transition) 對一個根視圖過渡的方法
  • TransitionManager.go(@NonNull Scene scene, @Nullable Transition transition) 對一個視圖圖層進行過渡的方法
  • TransitionManager.endTransitions(final ViewGroup sceneRoot) 結束全部根佈局的過渡

1.1 TransitionManager.beginDelayedTransition()

這個主要是針對根試圖的過渡方法:這裏主要是處理一個頁面中的過渡! 這個方法還有一個重載的方法:ide

beginDelayedTransition(@NonNull final ViewGroup sceneRoot)
beginDelayedTransition(@NonNull final ViewGroup sceneRoot, @Nullable Transition transition)
複製代碼
  • 參數1:根佈局
  • 參數2:相應的過渡動畫類型

這裏的動畫過渡類型有如下幾類:oop

  • AutoTransition 默認的樣式
  • Fade 淡入淡出
  • Explode 炸裂效果
  • Slide 移動

具體代碼以下:佈局

mCl_root = findViewById(R.id.cl_root);
        mTvText = findViewById(R.id.tv_text);
//        Slide slide = new Slide(Gravity.BOTTOM);
//        Explode explode = new Explode(); 
        Fade fade = new Fade();
        TransitionManager.beginDelayedTransition(mCl_root, fade);

        if (mTvText.getVisibility() == View.VISIBLE) {
            mTvText.setVisibility(View.GONE);
        } else {
            mTvText.setVisibility(View.VISIBLE);
        }
複製代碼

上面會有三種效果,這裏建議你們本身設置如下看看效果!測試

若是你想設置動畫的一些其餘屬性的話,能夠這樣:

fade.setDuration(300);//設置動畫時長
    fade.setInterpolator(new FastOutSlowInInterpolator());//設置插值器
    fade.setStartDelay(200);//設置延時
複製代碼

上面全部都有這些屬性的!!!

這裏注意一點,若是你想要使用縮放、顏色、旋轉變化的話,那個適配的庫中有!其實就是繼承了Transition這個類,本身去實現罷了!感興趣的童鞋能夠去試試。。。

1.2 TransitionManager.go()

說實話,這個東西我研究了很久,各類百度才理解了怎麼用,原諒個人愚笨。。。先說說我對這個東西的理解啊!從一個佈局文件過渡到另外一個佈局文件(注意,這裏是佈局文件的過渡)。我不知道怎麼用語言去形容。。。

我們看圖吧!

展現效果

上面的圖你們都看懂了吧!其實就是兩個佈局文件的過渡,中間全部的過渡都是TransitionManager幫咱們封裝完成的,你能夠選擇相應的樣式進行顯示!咱們看看具體的代碼實現吧!

首先要給你們說個類,這個類在此過分動畫中起着相當重要的做用,這個類就是Scene,註釋裏解釋爲一個視圖層次,也就至關於上面提到的佈局文件過渡中的佈局,其實這個東西你理解成佈局也是能夠的!

Scene getSceneForLayout(@NonNull ViewGroup sceneRoot, @LayoutRes int layoutId, @NonNull Context context)
複製代碼
  • 參數1:根佈局(操做的視圖層次所在的佈局的跟標籤)
  • 參數2:視圖層級佈局的索引
  • 參數3:根佈局

這樣就能夠建立一個相應的視圖層級了!下面咱們來講代碼:

由於是兩個佈局文件的過渡,因此這裏咱們須要一個總佈局,兩個供切換的佈局,這裏你可能不太明白,一會就明白了!!!相信我,不行你向我丟BUG;

  • 總佈局(根佈局)
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/cl_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.jinlong.newmaterialdesign.animation.TransitionManagerActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimaryDark"
        app:title="展現動畫效果"
        app:titleTextColor="@android:color/white" />

    <Button
        android:id="@+id/btn_animation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="animation"
        android:text="實現動畫變換"
        app:layout_constraintTop_toBottomOf="@id/toolbar" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="scene"
        android:text="變換動畫"
        app:layout_constraintLeft_toRightOf="@id/btn_animation"
        app:layout_constraintTop_toBottomOf="@id/toolbar" />

    <TextView
        android:id="@+id/tv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="20dp"
        android:text="請注意這些文字的變化"
        app:layout_constraintTop_toBottomOf="@id/btn_animation" />

   <FrameLayout
       android:id="@+id/rl_root"
       android:layout_width="match_parent"
       app:layout_constraintTop_toBottomOf="@id/tv_text"
       android:layout_height="200dp">

       <include layout="@layout/scene1" />
   </FrameLayout>
</android.support.constraint.ConstraintLayout>
複製代碼

這裏主要看FrameLayout中包裹的那個佈局,這是一個佈局文件!都是基於這裏來的!!!

  • 佈局1
<?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="200dp">

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/civ_1"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:src="@mipmap/heard_1" />

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/civ_2"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="20dp"
        android:layout_marginRight="20dp"
        android:src="@mipmap/heard_2" />

</RelativeLayout>
複製代碼
  • 佈局2
<?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="200dp">

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/civ_2"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:src="@mipmap/heard_2" />

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/civ_1"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="20dp"
        android:layout_marginRight="20dp"
        android:src="@mipmap/heard_1" />

</RelativeLayout>
複製代碼

兩個佈局的展示形式是這樣的。仔細的小夥伴可能看到了,兩個佈局的展現形式是同樣的,只是兩個控件的位置互換了一下。其實動畫的表現形式就是那個男孩的頭像從左上角移動到右下角,女孩的頭像從右下角移動到左上角,正好的兩個佈局的展示形式。因此講到這裏我像你就會明白爲何我一直強調是佈局文件的移動了吧!

  • 代碼實現 初始化視圖圖層
FrameLayout layout = findViewById(R.id.rl_root);
    mScene1 = Scene.getSceneForLayout(layout, R.layout.scene1, this);
    mScene2 = Scene.getSceneForLayout(layout, R.layout.scene2, this);
    TransitionManager.go(mScene1);
複製代碼

這裏建立了兩個視圖層次,開始的時候,直接默認顯示到視圖圖層1,點擊按鈕進行以下操做:

TransitionManager.go(isScene2 ? mScene1 : mScene2,new ChangeBounds());
    isScene2 = !isScene2;
複製代碼

這裏經過一個變量進行判斷,若是顯示的是視圖圖層2就切換到圖層1,不然相反!就能實現上面的效果了!!!總體代碼就不貼了,本身動手試一下,這樣記得牢靠!其實不僅侷限於這種表現形式。若是三個的話,你建立三個視圖圖層也是能夠切換的。這個你就要發揮想象空間了!

2.TransitionSet類介紹

關於這個類,能夠簡單理解爲動畫集合,能夠合併多個動畫一塊兒顯示出來。

TransitionSet transitionSet = new TransitionSet();
    transitionSet.addTransition(slide);
    transitionSet.addTransition(fade);
複製代碼

這樣就能直接把上面的過渡疊加起來了!

2.1 TransitionSet的XML使用

這裏我以爲有必要說明如下xml的使用,首先要明確,這個佈局的放置位置res/transition/xxx.xml。這裏先貼一個總體的xml我在逐一講解:

<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
    android:transitionOrdering="sequential"><!--是否按照順序執行-->

    <fade android:duration="500">
        <targets>
            <target android:targetId="@id/toolBar"/>
            <target android:targetId="@android:id/statusBarBackground"/>
            <target android:targetId="@id/tv_show"/>
        </targets>
    </fade>
    
    <slide android:startDelay="600">
        <targets>
            <target android:targetId="@id/icon_sf"/>
        </targets>
    </slide>
    
    <slide android:startDelay="700">
        <targets>
            <target android:targetId="@id/icon_bh"/>
        </targets>
    </slide>

    <slide
        android:slideEdge="left"
        android:startDelay="500">
        <targets>
            <target android:targetId="@id/tv_show"/>
        </targets>
    </slide>
</transitionSet>
複製代碼
  • android:transitionOrdering 表明執行順序
    • sequential 順序執行(寫在上面的先執行)
    • together 一塊兒執行
  • fade標籤 漸變的屬性
  • slide標籤 移動的屬性
  • changeBounds標籤
    • targets標籤 這個裏面主要是維護相應的那個控件須要過渡
      • android:excludeId 除去那個ID的控件不進行過渡(通常用於狀態欄,@android:id/statusBarBackground狀態欄的ID)
  • android:startDelay 延時的時間

基本上能用到的屬性就這麼多!!!其實這個清單文件裏面主要維護的是哪一個控件須要那種過渡。就醬紫!!!

講了這麼多你是否是仍是一臉懵逼,其實我也是,不知道怎麼去表達,因此我準備用實例去講解,便於本身的記憶和你的理解!!!

3.過渡動畫的案例分析:

終於到了本文的重點了,其實我開始學這個東西的時候也是一臉懵逼,不太理解,可是後來看到代碼的時候,就不那麼費勁了。。。。先從首頁頂部那個圖片開始提及吧!

3.1 頂部過渡動畫的實現

關於上面的動畫效果,主要記住共享這個概念,爲何這麼說呢?由於上面這個動畫是根據共享去關聯的。所謂的依靠共享,主要是這個View過渡到下一個View的相應展示形式!那麼就存在一個問題了,共享你必須兩個View有共同的一個View,而後存在共同的ID。不然下個頁面怎麼知道你想要拿什麼和我共享呢?這裏暫時定一下Activity頁面A(後面用A代替)和Activity頁面B(後面用B代替)。

  • A頁面的佈局
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/cl_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.jinlong.newmaterialdesign.animation.TransitionManagerActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimaryDark"
        app:title="展現動畫效果"
        app:titleTextColor="@android:color/white" />

    <LinearLayout
        android:id="@+id/ll_shared"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="20dp"
        android:onClick="sharedAnimation"
        android:orientation="horizontal"
        app:layout_constraintTop_toBottomOf="@id/toolbar">

        <de.hdodenhof.circleimageview.CircleImageView
            android:id="@+id/civ_heard"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:src="@mipmap/heard_1" />

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:layout_marginLeft="30dp"
            android:text="這是一個標題欄目" />
    </LinearLayout>
</android.support.constraint.ConstraintLayout>
複製代碼

這裏注意上面的CircleImageView控件的ID和TextView控件的ID,上面說了,後面會用到!

  • B頁面的佈局是這樣的
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.jinlong.newmaterialdesign.animation.SharedActivity">


    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimaryDark"
        app:title="展現動畫效果"
        app:titleTextColor="@android:color/white" />


    <LinearLayout
        android:id="@+id/fl_top"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:gravity="center"
        android:orientation="vertical"
        app:layout_constraintTop_toBottomOf="@id/toolbar">

        <de.hdodenhof.circleimageview.CircleImageView
            android:id="@+id/civ_heard"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/heard_1"
            android:transitionName="shared_image" />

        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:text="這也是相應的標題"
            android:transitionName="shared_textview" />
    </LinearLayout>
</android.support.constraint.ConstraintLayout>
複製代碼

這裏的ID和上面的ID是同樣的。而且注意這裏面設置的transitionName標籤,這個標籤是設置共享內容的,立刻你就會知道爲何了。。。

  • 經過代碼進行相應的跳轉
CircleImageView civHead = findViewById(R.id.civ_heard);
        TextView tvTitle = findViewById(R.id.tv_title);

        Intent intent = new Intent(this, SharedActivity.class);
        ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(this,
                new Pair<View, String>(civHead, "shared_image"),
                new Pair<View, String>(tvTitle, "shared_textview"));
        startActivity(intent, optionsCompat.toBundle());
複製代碼

3.1.1方法說明:

  • ActivityOptionsCompat makeSceneTransitionAnimation(Activity activity, Pair<View, String>... sharedElements)
  • ActivityOptionsCompat makeSceneTransitionAnimation(Activity activity, View sharedElement, String sharedElementName) 這個個方法是實現共享元素平移到第二個頁面的主要方法,兩個方法主要區別就是上面的能夠共享多個View,下面的只能共享一個View (注意這個只有在21以上的版本纔有效)
  • ActivityOptionsCompat makeCustomAnimation(Context context, int enterResId, int exitResId) 這個相似於以前的overridePendingTransition的效果,傳入的參數也都基本上同樣
  • ActivityOptionsCompat makeScaleUpAnimation(View source, int startX, int startY, int startWidth, int startHeight) 從頁面的具體那個矩形,開始放大到相應的屏幕位置,這裏面的參數,基本上都是和相應的矩形有關!
  • ActivityOptionsCompat makeThumbnailScaleUpAnimation(View source, Bitmap thumbnail, int startX, int startY) 縮略圖從指定的位置擴展到全屏。用於圖片的顯示應該挺好的!

看了上面的內容,我相信你能寫出下面的動畫效果了!

虛擬機效果錄得不怎麼好

3.2 後面那個擴散圓形的效果

其實後面那個圓形擴散的效果是在5.0之後纔有的效果(使用的是ViewAnimationUtils),因此要使用的話,必須在5.0機器上測試。不然是沒有效果的!!!代碼是這樣的...

Animator circularReveal = ViewAnimationUtils.createCircularReveal(mImage_bg, 0, mImage_bg.getHeight(), 0, Math.max(mImage_bg.getHeight(), mImage_bg.getWidth()));
                    mImage_bg.setBackgroundColor(Color.BLACK);
                    circularReveal.setDuration(600);
                    circularReveal.start(); 
複製代碼

其實用到的只有一個API方法Animator createCircularReveal(View view, int centerX, int centerY, float startRadius, float endRadius) 這裏面的參數基本上就是中心點座標,擴散半徑的肯定,這裏就不作太多解釋了!這個你能夠在在21的版本試一下就能夠了!

3.3 進入動畫的設置

在B頁面其實也是能夠設置相應的入場動畫的

  • getWindow().setEnterTransition(Transition transition); 設置入場時候的動畫
  • getWindow().setReturnTransition(Transition transition); 設置返回時候的動畫
  • getWindow().setSharedElementEnterTransition(Transition transition); 設置進入時存在共享的動畫
  • getWindow().setSharedElementReturnTransition(Transition transition) 設置返回時存在共享的動畫

穿插一個問題,就是Transition怎麼從xml中引入

TransitionInflater.from(this).inflateTransition(R.transition.return_slide)
複製代碼

這裏的Transition能夠是一個具體的子類,也能夠是一個清單文件。剩下的就是發揮你們的想象空間了!把上面的頁面剩下的代碼貼一下,就結束今天的內容吧!感受篇幅有點長,感興趣的同窗,能夠看看我GitHub裏面的項目!!!


這篇文章我寫了好幾天,不知道該怎麼去寫,感受寫的有點亂,但願你們不要介意,有什麼不懂的留言給我,我必定及時回覆......今天就醬紫了!

相關文章
相關標籤/搜索