Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 創建Material Design風格的Android應用--使用自定義動畫

創建Material Design風格的Android應用--使用自定義動畫

編輯:關於Android編程

動畫在Material Design設計中給用戶反饋放用戶點擊時,並且在程序用戶界面中提供連貫的視覺。Material主題為按鈕(Button)和activity的轉換提供了一些默認的動畫,在android5.0(api 21)和更高的版本,你可以自定義這些動畫和創建一個新動畫:

  • Touch feedback(觸摸反饋)
  • Circular Reveal(循環揭露效果)
  • Activity transitions(Activity轉換效果)
  • Curved motion(曲線運動)
  • View state changes (視圖狀態改變)

    自定義觸摸反饋

    觸摸反饋在Material Design中在觸摸點提供了一個即時視覺確認當用戶作用在UI元素。按鈕的默認觸摸反饋動畫是使用了新的RippleDrawable類,它會是波紋效果在不同狀態間變換。

    大多數情況下,我們可以使用這個功能通過在xml文件中定義背景:

    ?android:attr/selectableItemBackground 有界限的波紋
    ?android:attr/selectableItemBackgroundBorderless 可以超出視圖區域的波紋
    ?android:attr/selectableItemBackgroundBorderless 是21新添加的api

    另外,還以使用ripple元素定義RippleDrawable作為一個xml資源。

    你可以給RippleDrawable對象分配一個顏色。使用主題的android:colorControlHighlight屬性可以改變默認的觸摸反饋顏色。

    更多信息,查看RippleDrawable類的api指南。

    使用揭露效果

    揭露動畫為用戶提供視覺上的持續性擋顯示或者隱藏一組界面元素。ViewAnimationUtils.createCircularReveal()方法使你可以使用動畫效果來揭露或者隱藏一個視圖。

    這樣揭露一個先前隱藏的視圖:

    ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // previously invisible view View myView = findViewById(R.id.my_view); // get the center for the clipping circle int cx = (myView.getLeft() + myView.getRight()) / 2; int cy = (myView.getTop() + myView.getBottom()) / 2; // get the final radius for the clipping circle int finalRadius = Math.max(myView.getWidth(), myView.getHeight()); // create the animator for this view (the start radius is zero) Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius); // make the view visible and start the animation myView.setVisibility(View.VISIBLE); anim.start();

    這樣隱藏一個先前顯示的視圖:

    ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 // previously visible view final View myView = findViewById(R.id.my_view); // get the center for the clipping circle int cx = (myView.getLeft() + myView.getRight()) / 2; int cy = (myView.getTop() + myView.getBottom()) / 2; // get the initial radius for the clipping circle int initialRadius = myView.getWidth(); // create the animation (the final radius is zero) Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0); // make the view invisible when the animation is done anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); myView.setVisibility(View.INVISIBLE); } }); // start the animation anim.start();

    自定義activity轉換效果

    activity間轉換在Material Design程序中提供不同狀態間的視覺連接通過在公用元素上動作或者轉換。你可以為進入或退出的轉換自定義動畫,共享元素在不同的activity之間的轉換效果。
    進入過渡決定activity中的視圖怎樣進入場景。比如在爆裂進入過渡效果中,視圖從屏幕外面飛向屏幕中間進入場景。

    退出過渡決定activity中的視圖怎樣退出場景。比如,在爆裂退出過渡效果中,視圖從中間向遠處退出場景。
    共享元素過渡決定兩個activity之間共享的視圖怎麼在兩個activity之間過渡。比如,兩個activity有一個相同的圖片,在不同的位置和不同的大小,changeImageTransform(圖片變換變化)讓共享元素平滑的平移和縮放圖片在兩個activity之間。

    android 5.0(api 21)提供以下進入和退出效果:

    • explode(爆裂) - 從場景中間移動視圖進入或者退出
    • slide(滑動) - 視圖從場景的一個邊緣進入或者退出
    • fade(淡入淡出) - 從場景添加或者移除一個視圖通過改變他的透明

      所有過渡效果都繼承Visibility類,因此支持作為一個進入或者退出過渡效果。

      更多細節,看Transition類的api指南。

      Android5.0(api 21)也支持共享元素過渡效果:

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

        當你在程序中開啟activity間的過渡動畫時,默認的交叉淡入淡出效果會在兩個activity之間激活。

        共享元素動畫

        一個共享元素過渡效果

        指定過渡效果

        首先,使用在從material theme繼承的樣式中,使用android:windowContentTransitions屬性開啟窗口內內容過渡效果。也可以在樣式定義中第一進入,退出,共享元素的效果:

        ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <style name=BaseAppTheme parent=android:Theme.Material> <item name=android:windowContentTransitions>trueitem> <item name=android:windowEnterTransition>@transition/explodeitem> <item name=android:windowExitTransition>@transition/explodeitem> <item name=android:windowSharedElementEnterTransition> @transition/change_image_transformitem> <item name=android:windowSharedElementExitTransition> @transition/change_image_transformitem> style>

        示例中的過渡change_image_transform定義如下:

        ? 1 2 3 4 5 <transitionSet xmlns:android=http://schemas.android.com/apk/res/android> <changeImageTransform/> transitionSet>

        changeImageTransform元素對應ChangeImageTransform類。更多信息,查看Transition的api指南。

        在代碼中啟用窗口內容過渡效果,使用Window.requestFeature()方法:

        ? 1 2 3 4 5 // inside your activity (if you did not enable transitions in your theme) getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); // set an exit transition getWindow().setExitTransition(new Explode());

        在代碼中定義過渡效果,使用下面的方法,並傳一個Transition對象:

        • Window.setEnterTransition()
        • Window.setExitTransition()
        • Window.setSharedElementEnterTransition()
        • Window.setSharedElementExitTransition()

          setExitTransition()setSharedElementExitTransition()方法為調用的activity定義退出過渡效果,setEnterTransition()setSharedElementEnterTransition()方法為調用的activity定義進入過渡效果。

          為了達到完整的過渡效果,必須在進入的和退出的兩個activity上都啟用window內容過渡。否則,正調用的activity會開始退出過渡,你就會看到窗口過渡效果(比如縮放,或者淡出)。

          更快的開始一個進入過渡,使用Window.setAllowEnterTransitionOverlap()方法在被調用的activity。這讓你有更加激動人心的進入過渡效果。

          打開activity使用過渡

          如果你為一個activity開啟過渡並且設置了一個退出過渡效果,過渡效果會在你打開其他activity的時候激活,像這樣:

          ? 1 2 startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());

          如果你給第二個activity設置了進入過渡動畫,過渡也會在第二個activity啟動的時候激活。當你啟動其他的activity時,如果需要禁用過渡效果,提供一個為null的bundle選項。

          打開一個activity包含一個共享元素

          使用一個場景過渡動畫在兩個activity之間包括一個共享元素:

          1. 在theme中開啟窗口內容過渡效果
          2. 在style中指定一個共享元素過渡效果
          3. 在xml中定義過渡樣式
          4. 在兩個activity的樣式文件中給共享元素分配一個相同的名字使用android:transitionName屬性
          5. 使用ActivityOptions.makeSceneTransitionAnimation()方法。 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // get the element that receives the click event final View imgContainerView = findViewById(R.id.img_container); // get the common element for the transition in this activity final View androidRobotView = findViewById(R.id.image_small); // define a click listener imgContainerView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(this, Activity2.class); // create the transition animation - the images in the layouts // of both activities are defined with android:transitionName=robot ActivityOptions options = ActivityOptions .makeSceneTransitionAnimation(this, androidRobotView, robot); // start the new activity startActivity(intent, options.toBundle()); } });

            對於在代碼中生成的動態共享視圖,使用`View.setTransitionName()方法在兩個activity中給指定相同的名字。

            當完成第二個activity的時候,如果需要逆轉該過渡動畫,使用Activity.finishAfterTransition()方法代替Activity.finish()

            打開一個activity包含多個共享元素

            使用一個場景過渡動畫在兩個activity之間包括多於一個共享元素,在兩個activity中定義所有的的共享元素使用android:transitionName屬性(或使用View.setTransitionName()方法在所有的activity中),並且創建一個像下面這樣的ActivityOptions對象:

            ? 1 2 3 ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, Pair.create(view1, agreedName1), Pair.create(view2, agreedName2));

            使用曲線運動

            Material Design中,動畫依賴時間插值和空間移動模式曲線。在android5.0(api 21)和更高版本,你可以為動畫自定義時間曲線和移動曲線。

            PathInterpolator類是一個新的基於貝塞爾曲線或Path對象的插值器。這個插值器在1*1的正方形上定義了曲線運動,以(0,0)和(1,1)點作為錨點,根據夠照參數控制點。你也可以使用xml文件的定義一個路徑插值器,如:

            ? 1 2 3 4 5 <pathInterpolator xmlns:android=http://schemas.android.com/apk/res/android android:controlX1=0.4 android:controlY1=0 android:controlX2=1 android:controlY2=1/>

            Material Design設計規范中,系統提供了三個基本曲線的xml資源:

            • @interpolator/fast_out_linear_in.xml
            • @interpolator/fast_out_slow_in.xml
            • @interpolator/linear_out_slow_in.xml

              我們可以給Animator.setInterpolator()傳一個PathInterpolator對象來設置。

              ObjectAnimator類有新的構造方法,你可以一次使用兩個或者屬性使用path獨立於坐標動畫。比如,下面的動畫使用一個Path對象去動作一個視圖的x和y屬性:

              ? 1 2 3 4 ObjectAnimator mAnimator; mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path); ... mAnimator.start();

              視圖狀態改變動畫

              StateListAnimator定義動畫當視圖的狀態改變的時候運行,下面的例子是怎麼在xml中定義一個StateListAnimator動畫:

              ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <selector xmlns:android=http://schemas.android.com/apk/res/android> <item android:state_pressed=true> <set> <objectAnimator android:propertyName=translationZ android:duration=@android:integer/config_shortAnimTime android:valueTo=2dp android:valueType=floatType/> set> item> <item android:state_enabled=true android:state_pressed=false android:state_focused=true> <set> <objectAnimator android:propertyName=translationZ android:duration=100 android:valueTo=0 android:valueType=floatType/> set> item> selector>

              給視圖附加自定義的視圖狀態動畫,使用selector元素在xml文件中定義一個動畫祥例子中這樣,給視圖分配動畫使用android:stateListAnimator屬性。在代碼中使用,使用AnimationInflater.loadStateListAnimator()方法,並且使用View.setStateListAnimator()方法。

              當你的主題是繼承的Material主題,按鈕默認有一個Z動畫。如果需要避免這個動畫,設置android:stateListAnimator屬性為@null 即可。

              AnimatedStateListDrawable類讓你創建可繪制圖在相關聯的視圖狀態改變。android5.0的一些系統組件默認使用這些動畫。下面的例子是如何在xml文件中定義一個AnimatedStateListDrawable:

              ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <animated-selector xmlns:android=http://schemas.android.com/apk/res/android> <item android:id=@+id/pressed android:drawable=@drawable/drawableP android:state_pressed=true/> <item android:id=@+id/focused android:drawable=@drawable/drawableF android:state_focused=true/> <item android:id=@id/default android:drawable=@drawable/drawableD/> <transition android:fromId=@+id/default android:toId=@+id/pressed> <animation-list> <item android:duration=15 android:drawable=@drawable/dt1/> <item android:duration=15 android:drawable=@drawable/dt2/> ... animation-list> transition> ... animated-selector>

              可繪矢量動畫

              可繪制矢量圖在拉伸時不會失真。AnimatedVectorDrawable類讓你可以在可繪制矢量圖上面作用動畫。

              通常需要在三個xml文件中定義可動的矢量圖:

              一個矢量圖使用元素,放在res/drawable/下。
              一個可動的矢量圖使用元素,放在res/drawable/下。
              一個或更多個動畫對象使用元素,放在res/anim/下。

              可動矢量圖可以使用元素。元素定義一系列路徑或者子組,元素定義可繪圖的路徑。

              當你定義了一個想要作用動畫的矢量可繪制圖,使用android:name屬性給每個group和path指定一個唯一的名字,這樣你可以從動畫的定義中找到他們。比如:

              ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <vector xmlns:android=http://schemas.android.com/apk/res/android android:height=64dp android:width=64dp android:viewportHeight=600 android:viewportWidth=600> <group android:name=rotationGroup android:pivotX=300.0 android:pivotY=300.0 android:rotation=45.0 > <path android:name=v android:fillColor=#000000 android:pathData=M300,70 l 0,-70 70,70 0,0 -70,70z /> group> vector>

              可動的矢量繪制通過剛剛說到定義的名字,來找到這些path和group:

              ? 1 2 3 4 5 6 7 8 9 10 <animated-vector xmlns:android=http://schemas.android.com/apk/res/android android:drawable=@drawable/vectordrawable > <target android:name=rotationGroup android:animation=@anim/rotation /> <target android:name=v android:animation=@anim/path_morph /> animated-vector>

              動畫的定義表現在ObjectAnimator和AnimatorSet對象中。第一個動畫在這個例子中是讓目標組旋轉360度:

              ? 1 2 3 4 5 6 <objectAnimator android:duration=6000 android:propertyName=rotation android:valueFrom=0 android:valueTo=360 />

              第二個動畫例子是把矢量可繪圖從一個形狀變成另一種。所有的路徑必須兼容變換:他們必須有相同數量的命令,每個命令要有相同的參數。

              ? 1 2 3 4 5 6 7 8 9 <set xmlns:android=http://schemas.android.com/apk/res/android> <objectAnimator android:duration=3000 android:propertyName=pathData android:valueFrom=M300,70 l 0,-70 70,70 0,0 -70,70z android:valueTo=M300,70 l 0,-70 70,0 0,140 -70,0 z android:valueType=pathType /> set>

              更多的信息,看AnimatedVectorDrawable的api指南。

              PS後記

              這個系列終於寫完了,說實話基本上大部分都是翻譯的谷歌的官方文檔。因為時間問題,再加上自己的英語夠爛,最近越來慢。不過,這樣一下來,加上自己的一些代碼練習,對於Material設計算是能夠基本使用了。可惜,大部分的style還都不能向下兼容,只好等5了。

              網上有一些大神進來已經開源了一些開源組件,大家可以借此曲線救國,下次有空在專門整理一下。

               

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved