Android MotionLayout動畫:續寫ConstraintLayout新篇章

MotionLayout做爲ConstraintLayout子類,在ConstraintLayout 2.0庫被引入,主要用來管理運動和組件的動畫。ConstrantLayout約束佈局,用過的人都說好,反正我用着挺爽的。有部分同窗說性能問題,其實對於初中級開發者來講,暫無需考慮這個,相比本身動手嵌套幾層佈局強吧,並且更重要的是業務UI的實現,尤爲工做量大的時候。android

本文屬於入門級別,重點在於掃盲和入門。若是對你有用,歡迎點贊。我的能力有限,有些東西可能理解不透或不對,歡迎指正,很是感謝。bash

配置app

須要將ConstraintLayout的版本升級到2.0+。佈局

AndroidX:post

implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta8'
複製代碼

支持庫:性能

implementation 'com.android.support.constraint:constraint-layout:2.0.0-beta8'
複製代碼

學習MotionLayout動畫可能須要點TransitionConstraintLayout知識點,不瞭解能夠看看文末連接哦。MotionLayout運動動畫定義了在兩個狀態集(StateSet)或者兩個約束集(ConsraintSet)之間如何進行過渡。狀態集與約束集只是過渡動畫不一樣的組織方式。學習

若是快速入手

一、經過Android Studio建立名爲activity_motionMotionLayout佈局文件。 動畫

二、 生成 MotionLayout佈局後會報紅,提示建立 MotionScene.xml文件。

三、選擇建立後,會在 res/xml文件夾下生成 activity_motion_scene.xml文件。內容:

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <ConstraintSet android:id="@+id/start">
        <Constraint android:id="@+id/widget" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint android:id="@id/widget" />
    </ConstraintSet>

    <Transition
        app:constraintSetEnd="@id/end"
        app:constraintSetStart="@+id/start" />
</MotionScene>
複製代碼

此時在activity_motion.xml佈局文件中的MotionLayout標籤會多一個layoutDescription="@xml/activity_motion_scene"屬性,但Android Studio仍是缺乏layoutDescription屬性的錯誤,須要手動添加上命名空間spa

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/activity_motion_scene">

</androidx.constraintlayout.motion.widget.MotionLayout>
複製代碼

歐力給,已經學會建立MotionLayout,但好像沒什麼卵用。咱們來看看剛剛自動生成的activity_motion_scene.xml文件。3d

劃重點】根標籤MotionScene有一個defaultDuration屬性,表示全部未指定時間的動畫的默認時間,默認爲300毫秒。MotionScene根標籤 必須包含Transition標籤,能夠有多個Transition標籤。Transition標籤是用來指定動畫的開始和結束狀態、任何中間狀態以及觸發動畫的動做,能夠理解爲一個Transition標籤對應一個動畫。同時,MotionScene標籤能夠包含TransitionSet標籤,這是可選的。TransitionSet標籤主要爲Transition標籤提供起始和結束狀態的位置和屬性。而TransitionSet標籤必須包含一個或多個Constraint子標籤。Constraint標籤用來定義佈局中某個View在動畫中某個狀態下位置(經過ConstraintLayout的相關屬性來約束)。

充分理解上段話的內容,下面經過實戰加深理解:

一、在activity_motion.xml佈局文件增長一個idvStartStatus的正方形View。並在根標籤MotionLayout添加showPaths="true"屬性,用來顯示正方形運動的路徑。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/activity_motion_scene"
    app:showPaths="true">

    <View
        android:id="@+id/vStartStatus"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@color/colorPrimary" />

</androidx.constraintlayout.motion.widget.MotionLayout>
複製代碼

2.將activity_motion_scene.xml文件中Constraint標籤的id值修改爲正方形的id,即vStartStatusConstraint標籤的id屬性值須要與要起動畫效果的Viewid保持一致,這樣Constraint標籤的全部屬性都會做用於該ViewConstraint標籤的屬性與ConstraintLayout的屬性是一致的,爲此,給正方形開始狀態增長一些屬性,使其位置水平居中,距離頂部50dp

<ConstraintSet android:id="@+id/start">
    <Constraint
        android:id="@+id/vStartStatus"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginTop="50dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    </Constraint>
</ConstraintSet>
複製代碼

由於idstartConstraintSet標籤關聯到Transition標籤的constraintSetStart屬性,因此它做爲動畫(目前只有一個動畫)的起始狀態。而idendConstraintSet標籤關聯到Transition標籤的constraintSetEnd屬性,因此它將做爲動畫的結束狀態。結束狀態咱們將正方形設置水平居中,距離底部50dp

<ConstraintSet android:id="@+id/end">
    <Constraint
        android:id="@id/vStartStatus"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginBottom="50dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent">
    </Constraint>
</ConstraintSet>
複製代碼

設置Constraint標籤時記得設置layout_widthlayout_height,否則是看不到正方形的。

  1. 到這一步,Transition標籤已經擁有開始和結束狀態了,就差觸發動畫開始的操做了。給Transition標籤增長onClick子標籤,表示點擊觸發動畫。onClick標籤增長clickAction屬性,值爲toggle,表示重複點擊時,動畫循環效果;增長targetId屬性,值爲@id/vStartStatus,表示點擊正方形視圖觸發過渡動畫。
<Transition
    app:constraintSetEnd="@id/end"
    app:constraintSetStart="@+id/start">
    <OnClick
        app:clickAction="toggle"
        app:targetId="@id/vStartStatus" />
</Transition>
複製代碼

此時activity_motion_scene.xml看起來是這樣子的。

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:defaultDuration="500">

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/vStartStatus"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginTop="50dp"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@id/vStartStatus"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginBottom="50dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent">
        </Constraint>
    </ConstraintSet>

    <Transition
        app:constraintSetEnd="@id/end"
        app:constraintSetStart="@+id/start">
        <OnClick
            app:clickAction="toggle"
            app:targetId="@id/vStartStatus" />
    </Transition>
</MotionScene>
複製代碼

效果圖

OK,看到這裏,你應該能夠建立個相似的MotionLayout動畫。還不行的話,須要回頭再看看。

下面講介紹一些標籤的屬性與效果。

標籤與屬性

Transition標籤

Transition標籤主要用來指定Motion場景中一個或多個動畫。即關聯到動畫對應的各類狀態和用戶交互動做。和過渡動畫是大同小異的。

經常使用屬性:

constraintSetStart:指定動畫初始狀態;

constraintSetEnd:指定動畫結束狀態;

duration:指定動畫時長;

autoTransiton:是否自動開啓動畫。取值有:animateToStart過渡到初始狀態、animateToEnd過渡到結束狀態、jumpToEnd跳到結束狀態、jumpToStart跳到初始狀態、none不開始狀態。默認狀況下是none,當設爲其餘值時,不用和用戶交互即自動開啓動畫。

motionInterpolator:插值器。取值有:linear線性、bounce彈簧、easeIn淡入、easeOut淡出、easeInOut淡入淡出;

transitionDisable:容許動畫功能。取值:falsetrue

layoutDuringTransition:動畫過程當中,MotionLayoutView調用reqeustLayout,是否作出響應。取值honorRequest響應、ignoreRequest忽略;(beta 4)

一、用戶交互的子標籤

Transition標籤經過一些子標籤,實現與用戶交互的行爲。例如上文的OnClick子標籤表示用戶的點擊行爲。

  • OnClick標籤:點擊場景中某個視圖,開始動畫效果。

  • OnSwipe標籤:表示在佈局上滑動時要執行的操做。因爲我的能力有限,一些屬性不能準備表達。

二、關鍵幀子標籤

在上文中,默認狀況下過渡動畫Transition標籤會關聯一個開始狀態和一個結束狀態的TransitionSet標籤。但咱們知道Transition標籤不只能夠建立初始狀態和結束狀態,還能夠建立中間狀態。這些中間狀態則由關鍵幀來構成,以實現更復雜的動畫效果。

KeyFrameSet標籤:用來指定某個中間狀態的位置和屬性。其實和過渡動畫的關鍵幀是同樣的概念。KeyFrameSet標籤含有KeyPositionKeyAttribute兩個子標籤,這些共同構成過渡動畫過程當中某特殊狀態的位置和屬性。

位置關鍵幀

KeyPosition標籤: 用來定義整個運動動畫中某個狀態的位置,相比於靜態的TransitionSet標籤來講,更加靈活。

重點屬性解釋:

framePosition:當前關鍵幀的位置,把整個運動動畫分紅100個位置,取值0到99,那麼初始狀態的位置就是0,結束狀態就是99。


keyPositionType:參考座標系的選擇,決定了percentXpercentY屬性取值的結果。

取值:parentRelative表示座標系基於父視圖。例如在開頭的demo,加上下面的關鍵幀:

<KeyFrameSet>
    <KeyPosition
        app:percentY="0.5"
        app:framePosition="50"
        app:motionTarget="@id/vStartStatus"
        app:keyPositionType="parentRelative"
        app:percentX="0.25" />
</KeyFrameSet>
複製代碼

代碼定義了運動動畫過程的中間位置framePosition="50",參考系選擇了相對父視圖座標keyPositionType="parentRelative"。因爲父視圖是全屏,因此座標系原點在屏幕的左上角,percentY="0.5"percentX="0.25"則表示正方形在父視圖高度的1/2,寬度1/4的位置。

效果圖

keyPositionType屬性改成 deltaRelative,即座標系選擇參照整個過渡動畫的位置,那麼起始狀態的位置就是原點(0,0),結束狀態的位置就是終點(1,1)。 這裏因爲原點和終點在x軸上的距離是0,因此 percentX="0.25"是沒有效果的。

效果圖:

keyPositionType屬性改成pathRelative,即座標系選擇參照整個運動路徑,即起始和終點的直線距離構成X軸,此時y軸就有正負之分,表示在X軸的左邊仍是右邊。x軸和y軸的長度都是等於路徑的長度。

例如代碼以下:

<KeyFrameSet>
    <KeyPosition
        app:framePosition="50"
        app:percentX="0.5"
        app:percentY="0.1"
        app:keyPositionType="pathRelative"
        app:motionTarget="@id/vStartStatus" />
</KeyFrameSet>
複製代碼

效果圖:

代碼以下, percentY改成 -1

<KeyFrameSet>
    <KeyPosition
        app:framePosition="50"
        app:percentX="0.5"
        app:percentY="-0.1"
        app:keyPositionType="pathRelative"
        app:motionTarget="@id/vStartStatus" />
</KeyFrameSet>
複製代碼

效果圖:


percentWidthpercentHeight屬性表示視圖自身大小,若是整個動畫過程當中,視圖大小不存在變化,是沒有效果的。例如文章開始的demo就是沒有效果的,能夠將正方形在起始狀態和結束狀態的大小改成不一致,就能夠看到效果。percentWidthpercentHeight屬性會致使sizePercent屬性失效。

屬性關鍵幀

KeyAttribute相對於位置關鍵幀,屬性關鍵幀更注重的是屬性,而不是某位置。例如常見的位移、旋轉動畫。 屬性有:

  • framePosition 關鍵幀位置
  • motionTarget 關聯視圖Id
  • transitionEasing 動畫速度
  • curveFit 選擇基於直線的路徑或基於單一速率的路徑
  • motionProgress 設置動畫進度
  • android:alpha 透明度
  • android:elevation 陰影,注意SDK版本
  • android:rotation 旋轉
  • android:rotationX 繞X軸旋轉
  • "android:rotationY" 繞Y軸旋轉
  • android:transformPivotX 旋轉或縮放的中心點X座標
  • android:transformPivotY 旋轉或縮放的中心點Y座標
  • transitionPathRotate
  • android:scaleX" X軸縮放
  • android:scaleY" Y軸縮放
  • android:translationX X軸平移
  • android:translationY Y軸平移
  • android:translationZ X軸平移

若是以上屬性不夠,也能夠經過添加CustomAttribute子標籤實現本身屬性,跟屬性動畫自定屬性是同個概念。

自定義屬性

CustomAttribute標籤必須經過attributeName屬性指定一個屬性名。支持下類型的屬性。

  • customColorValue 顏色值類型
  • customColorDrawableValue顏色值的Drawable類型
  • customIntegerValue int類型
  • customFloatValue float類型
  • customStringValue String類型
  • customDimension 尺寸類型
  • customPixelDimension Pixel尺寸類型
  • customBoolean Boolean 類型

到這裏,Transition標籤和其子標籤、相關屬性基本就介紹完了。

ConstraintSet標籤

ConstraintSet約束集主要用來定義多個屬性集合,並經過id被Transition標籤引用,做爲運動動畫過程的起始或結束狀態。

Constraint標籤

子標籤Constraint用來該狀態某個View的相關約束屬性,約束屬性支持ConstraintLayout佈局的全部屬性+上文提到的自定義屬性。或者經過組織LayoutPropertySetTransformMotionCustomAttribute等子標籤,關於這些子標籤,感興趣能夠參閱官方文檔

系列好文推薦

Android屬性動畫,看完這篇夠用了吧

Android矢量圖動畫:每人送一輛掘金牌小黃車

Android過渡動畫,發現掘金小祕密

參考文章

官方文檔

中文官方文檔

點贊,方便往後查閱;點贊,碼字不易

相關文章
相關標籤/搜索