MotionLayout 運(yùn)動布局入門

MotionLayout,字面翻譯是叫運(yùn)動布局芦疏,它是一個能夠幫助我們在 app 中管理手勢和控件動畫的布局組件放仗。它是 ConstraintLayout 的子類并且基于它自身豐富的布局功能來進(jìn)行構(gòu)建桐早。既然是Layout驻子,自然會聯(lián)想到線性布局等等這些进肯。也能通過XML配置來實(shí)現(xiàn)一些動畫效果艇肴。本文參考至https://juejin.im/post/5d595328f265da03c34bfa59

它具有ConstraintLayout的所有屬性腔呜。MotionLayout用來處理兩個ConstraintSet之間的切換,并在根據(jù)兩個ConstraintSet的CustomAttribute參數(shù)來自動生成切換動畫再悼,關(guān)于ConstraintSet下面會討論核畴。同時MotionLayout所增加的是可以直接通過觸摸屏幕來控制動畫的運(yùn)行進(jìn)度。也就是說MotionLayout會管理你的觸摸事件通過跟蹤手指的速度冲九,并將其與系統(tǒng)中的視圖速度相匹配谤草。從而可以自然地在兩者之間通過觸摸滑動平穩(wěn)過渡。并且在動畫里面加入了關(guān)鍵幀的概念莺奸,使得其自動生成動畫在運(yùn)行時某一階段會運(yùn)行到關(guān)鍵幀的狀態(tài)丑孩。同時MotionLayout支持在XML中完全描述一個復(fù)雜的動畫,而不需要通過Java代碼來實(shí)現(xiàn)

動畫效果如下憾筏。

1.gif

我們先引入MotionLayout 庫

dependencies {
    implementation 'com.android.support.constraint:constraint-layout:2.0.0-beta2'
}

我們在布局中使用

<android.support.constraint.motion.MotionLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/step"
        app:motionDebug="SHOW_PATH"
        >

        <ImageView
            android:id="@+id/ball"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@mipmap/round"
            />

    </android.support.constraint.motion.MotionLayout>

可以看出這個布局需要內(nèi)嵌一些控件嚎杨,比如imageView,等氧腰,同時最關(guān)鍵的屬性是需要配置動畫MotionScene xml文件枫浙。這就類似于我們平常自定義的drawable文件。app:motionDebug="SHOW_PATH" 調(diào)試屬性是可以預(yù)覽動畫的運(yùn)動軌跡古拴。那么接下來就進(jìn)入step文件看看箩帚,

<?xml version="1.0" encoding="utf-8"?>
<!--describe the animation for activity_motion_sample_step1.xml-->
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:app="http://schemas.android.com/apk/res-auto">
    <!-- A transition describes an animation via start and end state -->
    <Transition
        app:constraintSetStart="@id/start"
        app:constraintSetEnd="@id/end"
        app:duration="2200">
        <OnClick
            app:targetId="@id/ball"
            app:clickAction="toggle" />
    </Transition>

    <!-- Constraints to apply at the start of the animation -->
    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/ball"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_marginStart="12dp"
            android:layout_marginTop="12dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"/>
    </ConstraintSet>

    <!-- Constraints to apply at the end of the animation -->
    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/ball"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_marginEnd="12dp"
            android:layout_marginBottom="12dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>
    </ConstraintSet>

</MotionScene>
因?yàn)镸otionLayout是繼承自ConstraintLayout,自然也有約束的屬性黄痪。所以包括ConstraintSet紧帕、Transition和StateSet。由于StateSet涉及篇幅較長桅打,這里暫沒有解釋是嗜。效果如下
2.gif

由此可以看出,Transition控制了icon 的起始位置挺尾,constraintSetStart控制了ConstrainSet命名為start的標(biāo)簽鹅搪,即為開始位置,constraintSetEnd控制了ConstrainSet命名為end的標(biāo)簽遭铺,即為結(jié)束的位置丽柿。動畫持續(xù)時間為2200毫秒恢准。以及子屬性中的OnClick時間,綁定了xml布局中的id為ball的imageView甫题。余下的一看便知馁筐。

那么如果像更復(fù)雜的做法,多個icon從同一個起始位置開始坠非,不同地方結(jié)束呢敏沉。比如下面這樣


4.gif

布局代碼是這樣

<android.support.constraint.motion.MotionLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layoutDescription="@xml/step2"
        app:motionDebug="SHOW_PATH"
        >

        <ImageView
            android:id="@+id/ic_android_blue"
            android:layout_width="42dp"
            android:layout_height="42dp"
            android:src="@mipmap/round"/>
        <ImageView
            android:id="@+id/ic_android_left"
            android:layout_width="42dp"
            android:layout_height="42dp"
            android:src="@mipmap/round"/>
        <ImageView
            android:id="@+id/ic_android_right"
            android:layout_width="42dp"
            android:layout_height="42dp"
            android:src="@mipmap/round"/>

        <TextView
            android:id="@+id/tipText"
            android:text="Swipe the blue android icon up"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginEnd="16dp"
            android:layout_marginTop="16dp"
            app:layout_constraintTop_toTopOf="parent"/>


    </android.support.constraint.motion.MotionLayout>

MotionScene為這樣

<?xml version="1.0" encoding="utf-8"?>
<!--describe the animation for activity_motion_sample_step2.xml-->
<!--animate by dragging target view-->
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:app="http://schemas.android.com/apk/res-auto">
    <!--At the start, all three stars are centered at the bottom of the screen.-->
    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/ic_android_blue"
            android:layout_width="42dp"
            android:layout_height="42dp"
            android:layout_marginBottom="20dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>
        <Constraint
            android:id="@+id/ic_android_left"
            android:layout_width="42dp"
            android:layout_height="42dp"
            android:alpha="0.0"
            android:layout_marginBottom="20dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>
        <Constraint
            android:id="@+id/ic_android_right"
            android:layout_width="42dp"
            android:layout_height="42dp"
            android:layout_marginBottom="20dp"
            android:alpha="0.0"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"/>
    </ConstraintSet>

    <!--Define the end constraint to set use a chain to position all three stars together below @id/tipText.-->
    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/ic_android_left"
            android:layout_width="58dp"
            android:layout_height="58dp"
            android:layout_marginEnd="90dp"
            android:alpha="1.0"
            app:layout_constraintHorizontal_chainStyle="packed"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toStartOf="@id/ic_android_blue"
            app:layout_constraintTop_toBottomOf="@id/tipText"/>
        <Constraint
            android:id="@+id/ic_android_blue"
            android:layout_width="58dp"
            android:layout_height="58dp"
            app:layout_constraintEnd_toStartOf="@id/ic_android_right"
            app:layout_constraintStart_toEndOf="@id/ic_android_left"
            app:layout_constraintTop_toBottomOf="@id/tipText"/>
        <Constraint
            android:id="@+id/ic_android_right"
            android:layout_width="58dp"
            android:layout_height="58dp"
            android:layout_marginStart="90dp"
            android:alpha="1.0"
            app:layout_constraintStart_toEndOf="@id/ic_android_blue"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tipText"/>
    </ConstraintSet>
    <!-- A transition describes an animation via start and end state -->
    <Transition
        app:constraintSetStart="@id/start"
        app:constraintSetEnd="@id/end">
        <!-- MotionLayout will track swipes relative to this view -->
        <OnSwipe app:touchAnchorId="@id/ic_android_blue"/>
    </Transition>
</MotionScene>

可以看到原來布局中是可以出現(xiàn)放置多個動畫資源的,而ConstrainSet標(biāo)簽中也可以對不同資源進(jìn)行編輯不同的起始位置麻顶。而Transition中的OnSwipe標(biāo)簽更是可以為我們動畫增加多了滑動手勢的動作赦抖。

目前只是簡單的平移動作舱卡。如果是曲線動畫辅肾,當(dāng)然可以。KeyFrameSet轮锥,它可以改變我們動畫過程中某個關(guān)鍵幀的位置以及狀態(tài)信息矫钓。


6.gif
<?xml version="1.0" encoding="utf-8"?>
<!--describe the animation for activity_motion_sample_step3.xml-->
<!--animate in the path way on a view-->
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
             xmlns:app="http://schemas.android.com/apk/res-auto">
    <!-- Constraints to apply at the start of the animation -->
    <ConstraintSet android:id="@+id/start">

        <Constraint
                android:id="@id/windmill"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_marginStart="12dp"
                android:layout_marginBottom="12dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"/>

        <Constraint
                android:id="@id/tipText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:alpha="0.0"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintBottom_toBottomOf="@id/windmill"
                app:layout_constraintTop_toTopOf="@id/windmill"/>
    </ConstraintSet>
    <!-- Constraints to apply at the end of the animation -->
    <ConstraintSet android:id="@+id/end">
        <!--this view end point should be at bottom of parent-->
        <Constraint
                android:id="@id/windmill"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_marginBottom="12dp"
                android:layout_marginEnd="12dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"/>
        <Constraint
                android:id="@+id/tipText"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginBottom="12dp"
                android:alpha="1.0"
                android:layout_marginEnd="72dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"/>
    </ConstraintSet>

    <!-- A transition describes an animation via start and end state -->
    <Transition
            app:constraintSetStart="@id/start"
            app:constraintSetEnd="@id/end">
        
        <KeyFrameSet>
            <KeyPosition
                    app:framePosition="50"
                    app:motionTarget="@id/windmill"
                    app:keyPositionType="parentRelative"
                    app:percentY="0.5"/>
            <!--apply other animation attributes-->
            <!--前半段的動畫效果:逆時針旋轉(zhuǎn)一圈,同時放大一倍-->
            <KeyAttribute
                    app:motionTarget="@id/windmill"
                    android:rotation="-360"
                    android:scaleX="2.0"
                    android:scaleY="2.0"
                    app:framePosition="50"/>
            <!--后半段的動畫效果:逆時針旋轉(zhuǎn)一圈舍杜,同時變回原樣-->
            <KeyAttribute
                    app:motionTarget="@id/windmill"
                    android:rotation="-720"
                    app:framePosition="100"/>
            <!--延遲動畫——0-85過程中將透明度一直維持在0.0-->
            <KeyAttribute
                    app:motionTarget="@id/tipText"
                    app:framePosition="85"
                    android:alpha="0.0"/>
        </KeyFrameSet>

        <OnSwipe
            app:touchAnchorId="@id/windmill"
            app:touchAnchorSide="bottom"
            app:dragDirection="dragRight"/>
    </Transition>

</MotionScene>

可以看出里面最關(guān)鍵的新娜,KeyFrameSet 需要被包含在 Transition 里面,同時 KeyFrameSet 中定義了 <KeyPosition> 和 <KeyAttribute> 兩種元素既绩,它們主要用來設(shè)置動畫某個位置的關(guān)鍵幀概龄,進(jìn)而為某段動畫指定所期望的效果。顧名思義饲握,KeyPosition 用于指定動畫某個關(guān)鍵幀的位置信息私杜,而 KeyAttribute 則用來描述動畫某關(guān)鍵幀的屬性配置(如:透明度、縮放救欧、旋轉(zhuǎn)等)衰粹,這樣就能構(gòu)成一個比較有趣的動畫效果。當(dāng)然KeyFrameSet還有很多別的屬性笆怠。這里就不一一講述了铝耻。可以自己研究下蹬刷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瓢捉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子办成,更是在濱河造成了極大的恐慌泡态,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诈火,死亡現(xiàn)場離奇詭異兽赁,居然都是意外死亡状答,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門刀崖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惊科,“玉大人,你說我怎么就攤上這事亮钦」萁兀” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵蜂莉,是天一觀的道長蜡娶。 經(jīng)常有香客問我,道長映穗,這世上最難降的妖魔是什么窖张? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蚁滋,結(jié)果婚禮上宿接,老公的妹妹穿的比我還像新娘。我一直安慰自己辕录,他們只是感情好睦霎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著走诞,像睡著了一般副女。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蚣旱,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天碑幅,我揣著相機(jī)與錄音,去河邊找鬼姻锁。 笑死枕赵,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的位隶。 我是一名探鬼主播拷窜,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼涧黄!你這毒婦竟也來了篮昧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤笋妥,失蹤者是張志新(化名)和其女友劉穎懊昨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體春宣,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酵颁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年嫉你,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躏惋。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡幽污,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出簿姨,到底是詐尸還是另有隱情距误,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布扁位,位于F島的核電站准潭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏域仇。R本人自食惡果不足惜刑然,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望殉簸。 院中可真熱鬧闰集,春花似錦、人聲如沸般卑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蝠检。三九已至,卻和暖如春挚瘟,著一層夾襖步出監(jiān)牢的瞬間叹谁,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工乘盖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留焰檩,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓订框,卻偏偏與公主長得像析苫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子穿扳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容