MotionLayout 介紹 (第一章)

原文鏈接

MotionLayout 是 ConstrainLayout 2.0 庫(kù)中被引入的一個(gè)新類,幫助安卓開發(fā)者關(guān)聯(lián)手勢(shì)和組件動(dòng)畫。接下來(lái)的文章將介紹會(huì)如何在應(yīng)用中添加和使用 MotionLayout 。

第一章將介紹MotionLayout的基礎(chǔ):

  • MotionLayout 是什么?
  • 將 ConstrainLayout 2.0 和 MotionLayout 添加到項(xiàng)目中
  • 如何使用 MotionLayout
  • ConstraintSets
  • MotionScene
  • 示例1: 關(guān)聯(lián)已有的布局文件
  • 處理 OnSwipe
  • 示例2: 自包含的 MotionScene
  • MotionLayout 屬性
  • 總結(jié)

你可以在這里查看示例的源碼 ConstraintLayout examples github repositor

MotionLayout 是什么?

安卓系統(tǒng)框架中已經(jīng)提供下面幾種方法在應(yīng)用中使用動(dòng)畫:

這一部分將介紹 MotionLayout 與這些動(dòng)畫的不同。

MotionLayout 就像它的名字一樣,首先它是一個(gè)布局,可以放置組件。其次它還是 ConstrainLayout 的子類,內(nèi)置豐富的功能。

創(chuàng)建 MotionLayout 的目的是用于降低布局過(guò)渡動(dòng)畫和復(fù)雜的手勢(shì)處理之間的難度,你可以認(rèn)為它擁有綜合屬性動(dòng)畫,TransitionManager, 和 CoordinatorLayout 的功能。

它擁有綜合屬性動(dòng)畫,TransitionManager, 和 CoordinatorLayout 的功能

使用 MotionLayout 你可以像 TransitionManager 一樣通過(guò)兩個(gè)布局文件描述布局的過(guò)渡動(dòng)畫,但是可以使用任何屬性(不僅僅局限于 layout attribute). 還有它支持可循跡的過(guò)渡,就像 CoordinatorLayout ( 可以通過(guò)滑動(dòng)即刻響應(yīng)過(guò)渡動(dòng)畫 ) 。它支持通過(guò)滑動(dòng)和關(guān)鍵幀自定義過(guò)渡動(dòng)畫。

MotionLayout 是完全聲明式的

MotionLayout 的另外一個(gè)關(guān)鍵區(qū)別是,它是完全聲明式的。只需要 XML 文件就可以描述一個(gè)復(fù)雜的過(guò)渡動(dòng)畫(如果你像通過(guò)代碼來(lái)描述動(dòng)畫,系統(tǒng)提供的屬性完全可以滿足需求)。

MotionLayout 工具

我們相信這種聲明式的規(guī)范將簡(jiǎn)化過(guò)渡動(dòng)畫,同時(shí)也有助于為 Android Studio 提供更好的圖形化工具。(我們現(xiàn)在正在積極的開發(fā)這樣的工具,它現(xiàn)在還不可用。)

img

最后,作為 ConstrainLayout 2.0 的一部分,它最低支持安卓 API 14,99.8%的設(shè)備都可以使用。

限制

不同于 TransitionManager ,MotionLayout 只能用于他的直接子組件。

何時(shí)使用MotionLayout

我們?cè)O(shè)想到的使用 MotionLayout 的使用場(chǎng)景: 當(dāng)你需要移動(dòng),縮放或者動(dòng)畫 實(shí)際的 UI 組件 (button,title bar 等) 來(lái)提供與用戶的互動(dòng)時(shí)。

將 ConstrainLayout 2.0 和 MotionLayout 添加到項(xiàng)目中

只需要將下面的代碼添加到 Gradle 文件中即可

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

如何使用 MotionLayout

MotionLayout 是 ConstrainLayout 的子類,因此你可以把它當(dāng)作一個(gè)普通的布局。 將已經(jīng)存在的 ConstrainLayout 布局轉(zhuǎn)換成 MotionLayout 布局 只需要將類名從:

<android.support.constraint.ConstraintLayout .../>

替換成

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

ConstrainLayout 和 MotionLayout 的主要不同是 MotionLayout 不是必須將實(shí)際描述信息包含在 XML 布局文件中。MotionLayout 通常將這些信息保存在一個(gè)單獨(dú)的 XML 文件 ( MotionScene) 中并關(guān)聯(lián)到布局文件, 通過(guò)這種方式布局文件只需要包含 View 和它們的屬性,無(wú)需包含位置信息和動(dòng)畫。

ConstraintSets

通常 ConstrainSet 將包含布局文件中的所有的位置信息規(guī)則; 你可以使用多個(gè) ConstrainSet, 你可以決定將那些規(guī)則應(yīng)用到布局中,在應(yīng)用時(shí)這些 View 不會(huì)被重建,只會(huì)修改他們的位置和大小。結(jié)合 TransitionManager 使用可以很容易的創(chuàng)建 ConstrainLayout 的動(dòng)畫。

MotionLayout 實(shí)際上也是源于這種思想,并添加了更豐富的功能。

MotionScene

MotionLayout 的規(guī)范保存在一個(gè)單獨(dú)的 MotionScene XML文件中,該文件存儲(chǔ)在 res / xml 目錄中。

img

一個(gè) MotionScene 文件可以包含動(dòng)畫所需的所用內(nèi)容:

  • 包含的 ConstraintSets
  • 這些 ConstraintSet 之間的轉(zhuǎn)換(transition)
  • 關(guān)鍵幀, 事件處理

例如,你可以將一個(gè) View 從屏幕的一側(cè)拖拽到另一側(cè):

img

示例1: 關(guān)聯(lián)布局文件

你需要使用 ConstrainLayout 創(chuàng)建兩個(gè) ConstrainSet 一個(gè)是初始位置(組件在屏幕的左面)一個(gè)是結(jié)束位置(組件在屏幕的右邊)

初始位置:

img
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/button"
        android:background="@color/colorAccent"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginStart="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

結(jié)束位置:

img
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/button"
        android:background="@color/colorAccent"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:layout_marginEnd="8dp"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

使用這兩個(gè)布局文件可以初始化兩個(gè) ConstrainSet ,并使用他們(如果使用 TransitionManager 會(huì)有動(dòng)畫的平滑過(guò)渡)。這種方式有一個(gè)問(wèn)題是轉(zhuǎn)化一旦開始就不會(huì)結(jié)束,你也不能告訴系統(tǒng)將轉(zhuǎn)換挺在某個(gè)位置 (你不能通過(guò)輸入事件控制轉(zhuǎn)換) 。

MotionLayout 解決了這些問(wèn)題。你可以使用 MotionLayout 做同樣的事,并且復(fù)用已存在的布局文件來(lái)初始化狀態(tài)。首先需要為組件創(chuàng)建一個(gè) MotionLayout 文件(motion_01_basic.xml ):

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/motionLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/scene_01"
    tools:showPaths="true">

    <View
        android:id="@+id/button"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:background="@color/colorAccent"
        android:text="Button"
        tools:layout_editor_absoluteX="147dp"
        tools:layout_editor_absoluteY="230dp" />

</androidx.constraintlayout.motion.widget.MotionLayout>

布局文件中引用了一個(gè) MotionScene 文件scene_01

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

    <Transition
        motion:constraintSetStart="@layout/motion_01_cl_start"
        motion:constraintSetEnd="@layout/motion_01_cl_end"
        motion:duration="1000">
        <OnSwipe
            motion:touchAnchorId="@+id/button"
            motion:touchAnchorSide="right"
            motion:dragDirection="dragRight" />
    </Transition>

</MotionScene>

scene_01 設(shè)置了默認(rèn)的轉(zhuǎn)換,設(shè)置了開始和結(jié)束 ConstrainSet (motion_01_cl_startmotion_01_cl_end ),并為轉(zhuǎn)換設(shè)置了OnSwipe 處理。

OnSwipe handler

scene_01.xml文件中我們?cè)?Transition 中設(shè)置了 OnSwipe 處理器。處理器通過(guò)匹配用戶的輸入事件控制轉(zhuǎn)換。

img

有一些屬性你需要了解:

touchAnchorId: 需要跟蹤的對(duì)象

touchAnchorSide: 跟蹤手指的一側(cè)(right / left / top / bottom)

dragDirection: 跟蹤手指運(yùn)動(dòng)的方向 ( dragRight / dragLeft / dragUp / dragDown 將決定進(jìn)度值的變化0-1)

示例2: 自包含的 MotionScene

示例1展示了如何快速的創(chuàng)建一個(gè) MotionLayout,最終使用了已存在的布局文件。MotionLayout 還支持直接在 MotionScene 文件中定義 ConstraintSet 。這樣做有有以下好處:

  • 一個(gè)文件可以包含多個(gè) ConstraintSet
  • 除了已有的功能外,還可以處理其他的屬性和自定義屬性
  • 面向未來(lái):即將到來(lái)的 Android Studio MotionEditor 可能只支持自包含 MotionScene 文件
插值屬性

MotionScene 文件中 ConstraintSet 元素可以使用的屬性不僅包含常用的布局屬性,除了位置和邊距下面的屬性也可以在 MotionLayout 中使用:

alpha
visibility
elevation
rotation, rotation[X/Y]
translation[X/Y/Z]
scaleX/Y

讓我們?yōu)槭纠?重新創(chuàng)建一個(gè)新的自包含的 MotionScene 文件。 MotionLayout 文件除了引用了新的 scene_02.xml 和實(shí)例1中沒(méi)有區(qū)別:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.motion.MotionLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/motionLayout"
    app:layoutDescription="@xml/scene_02"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/button"
        android:background="@color/colorAccent"
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:text="Button" />

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

MotionScene 文件中有明顯的區(qū)別, Transition 的設(shè)置相同,但是我們把 StartEnd直接定義在了 XML 文件中。 和普通布局文件相比主要的區(qū)別是我們沒(méi)有指定具體的組件,而是把限定屬性寫在了Constraint元素中。

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

    <Transition
        motion:constraintSetStart="@+id/start"
        motion:constraintSetEnd="@+id/end"
        motion:duration="1000">
        <OnSwipe
            motion:touchAnchorId="@+id/button"
            motion:touchAnchorSide="right"
            motion:dragDirection="dragRight" />
    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginStart="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/button"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginEnd="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

</MotionScene>

ConstraintSet

只需要將了解 ConstrainSet 是如何工作的,新的屬性將替換到關(guān)聯(lián)的組件上。 只需將需要替換的屬性全部包含到Constraint 中。通常這會(huì)清除組件上的所用屬性并將新的屬性賦值到組件上。

MotionLayout 的屬性

在開發(fā)中你可能會(huì)用到 MotionLayout 的下列屬性:

app:layoutDescription=”reference” 指定 MotionScene XML 文件

app:applyMotionScene=”boolean” 是否應(yīng)用 MotionScene [default=true]

app:showPaths=”boolean” 是否顯示路徑 [default=false]. 記得在發(fā)布版本中關(guān)閉

app:progress=”float” 指定轉(zhuǎn)換的進(jìn)度 [0-1]

app:currentState=”reference” 指定一個(gè) ConstraintSet

總結(jié)

第一篇文章包含了 MotionLayout 的基礎(chǔ)功能, 你可以在這里查看源碼ConstraintLayout examples github repository

接下來(lái)的文章中我們將包含更多的講解:

  • 自定義屬性, 圖片變換, 關(guān)鍵幀 (part II) 中文翻譯

  • 在現(xiàn)有的布局中使用 MotionLayout (CoordinatorLayout, DrawerLayout, ViewPager) (part III) 中文翻譯

  • 關(guān)于關(guān)鍵幀的所有! (part IV)

  • MotionLayout 作為根布局

  • 嵌套 MotionLayout & 其他的組件

  • MotionLayout 和 fragments

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 28,803評(píng)論 1 45
  • 原文地址:http://www.android100.org/html/201606/06/241682.html...
    AFinalStone閱讀 1,290評(píng)論 0 1
  • 對(duì)的,是這樣。慢慢的 慢慢的抓不住青春的尾巴了。
    TKYKB閱讀 137評(píng)論 0 0
  • 之前看秦海璐和劉濤的訪談節(jié)目,很感動(dòng)這種感情,我會(huì)想起阿笨以及每個(gè)階段遇見的閨蜜,但是離開家鄉(xiāng)太遠(yuǎn),很多年不見。漸...
    LP橋閱讀 241評(píng)論 0 1
  • 在《4.7 Eureka Server的高可用》中,我們構(gòu)建了一個(gè)雙節(jié)點(diǎn)的Eureka Server集群,本節(jié)我們...
    周立_itmuch閱讀 1,378評(píng)論 0 2

友情鏈接更多精彩內(nèi)容