來個有意思的,使用MotionLayout實(shí)現(xiàn)王者榮耀團(tuán)戰(zhàn)

1专酗、前言

昨晚跟往常一樣睹逃,飯后開了一局王者榮耀,前中期基本焦灼,到了后期一波決定勝負(fù)的時候沉填,我果斷射箭疗隶,射中對面,配合隊(duì)友直接秒殺翼闹,打贏團(tuán)戰(zhàn)一波推完基地斑鼻。那叫一個精彩,隊(duì)友都發(fā)出了666666的稱贊猎荠,我酷酷的點(diǎn)了一下抱拳:多謝坚弱!嘿嘿。

賽后关摇,手機(jī)上正在展示我的MVP動畫荒叶,我不禁思考,這么精彩的團(tuán)戰(zhàn)我怎么能不記錄下來输虱?剛好最近了解到MotionLayout庫些楣,就用它實(shí)現(xiàn)吧??。

動畫效果

2悼瓮、功能詳解

MotionLayout 是一種布局類型戈毒,可幫助您管理應(yīng)用中的運(yùn)動和微件動畫。MotionLayout 是 ConstraintLayout 的子類横堡,在其豐富的布局功能基礎(chǔ)之上構(gòu)建而成埋市。

如上述介紹,MotionLayout是 ConstraintLayout的子類命贴,相當(dāng)于加了動畫功能的ConstraintLayout道宅。MotionLayout作為一個動畫控件的好處就在于基本不用寫java代碼,全部在xml文件中搞定胸蛛。而且我們只需要設(shè)定起始位置污茵,結(jié)束位置以及一些中間狀態(tài),就能自動生成動畫葬项。

先分析下我們的團(tuán)戰(zhàn)泞当,主要分為三個場景:

后羿果斷射大,射中在瘋狂走位的亞瑟民珍。
妲己和鐘無艷同時在草叢蹲伏襟士,看到后羿的精彩射箭,從草叢走出嚷量,準(zhǔn)備大戰(zhàn)陋桂。
妲己2技能暈眩住對面的魯班七號,一套技能加上鐘無艷的大招蝶溶,將對面兩個英雄KO嗜历。

場景一

包含控件:后羿,亞瑟,魯班梨州,后羿的箭
動畫描述:走位的亞瑟痕囱,后羿射箭

首先在布局文件中,添加第一個MotionLayout暴匠,并添加上所有的控件咐蝇,后羿和魯班由于是靜止?fàn)顟B(tài),所以要寫上位置約束巷查,其他包含動畫的控件可以暫時不用寫位置約束:

<androidx.constraintlayout.motion.widget.MotionLayout
    android:id="@+id/motionLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/scene_01"
    app:showPaths="false"
    tools:showPaths="true">

    <ImageView
        android:id="@+id/houyi"
        android:layout_width="66dp"
        android:layout_height="66dp"
        android:layout_marginLeft="180dp"
        android:src="@drawable/houyi_model"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.8" />

    <ImageView
        android:id="@+id/houyi_arrow"
        android:layout_width="66dp"
        android:layout_height="66dp"
        android:src="@drawable/arrow" />

    <ImageView
        android:id="@+id/yase"
        android:layout_width="66dp"
        android:layout_height="66dp"
        android:src="@drawable/yase_model" />

    <ImageView
        android:id="@+id/luban"
        android:layout_width="66dp"
        android:layout_height="66dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.58"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.26"
        android:src="@drawable/luban_model" />

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

由于MotionLayout繼承自ConstraintLayout,所以可以用ConstraintLayout的屬性抹腿。這里可以看到有兩個新的屬性:

app:layoutDescription岛请,這個屬性就是代表該MotionLayout對應(yīng)的動畫場景,引用的是一個MotionScene(XML資源文件)警绩,其中就會包括相應(yīng)布局的所有運(yùn)動動畫描述崇败。
app:showPaths,這個屬性代表運(yùn)動進(jìn)行時是否顯示運(yùn)動路徑肩祥,也就是所有動畫的路徑是否顯示后室。默認(rèn)是false。代碼中也是可以設(shè)置是否顯示動畫路徑混狠,setDebugMode方法傳入MotionLayout.DEBUG_SHOW_PATH屬性即可岸霹。

后羿射箭

接下來就可以寫動畫場景(MotionScene)了,新建res-xml-scene_01.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">

    <Transition
        app:constraintSetEnd="@+id/end"
        app:constraintSetStart="@+id/start"
        app:duration="2000">

    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/houyi_arrow"
            android:layout_width="66dp"
            android:layout_height="66dp"
            android:layout_marginLeft="190dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.8">

        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/houyi_arrow"
            android:layout_width="66dp"
            android:layout_height="66dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.65"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.35">
        </Constraint>
    </ConstraintSet>

</MotionScene>

可以看到贡避,MotionScene有兩個主要的標(biāo)簽Transition和ConstraintSet

一、Transition予弧,包括運(yùn)動的基本定義刮吧,其中motion:constraintSetStart和motion:constraintSetEnd指的是運(yùn)動的起始狀態(tài)和結(jié)束狀態(tài)。分別就對應(yīng)下面ConstraintSet所配置的掖蛤。app:duration代表完成運(yùn)動所需的時間杀捻。
二、ConstraintSet蚓庭,多個控件的端點(diǎn)約束集合致讥,比如這里就有兩個ConstraintSet,分別代表起始約束集和結(jié)束約束集彪置。

其中Constraint屬性指定了端點(diǎn)位置中某一個元素的位置和屬性:

一拄踪、支持所有ConstraintLayout 屬性。
二拳魁、支持alpha惶桐,rotation,visibility,translationX姚糊,scaleX等view基本屬性贿衍。
三、支持自定義屬性救恨,用子標(biāo)簽CustomAttribute表示贸辈,舉個小栗子:

<Constraint
    android:id="@+id/button" ...>
    <CustomAttribute
        motion:attributeName="backgroundColor"
        motion:customColorValue="#D81B60"/>
</Constraint>

attributeName屬性就是與具有g(shù)etter和setter方法的對象匹配,比如這里的backgroundColor就對應(yīng)了view本身的基本方法getBackgroundColor() 和 setBackgroundColor()肠槽。

好了擎淤,回到后裔這邊,由于后羿的箭是從后羿位置到亞瑟位置秸仙,所以我們設(shè)定好后羿箭的兩個端點(diǎn)狀態(tài)嘴拢,配置好后,MotionLayout就會自動幫我們生成從起始狀態(tài)到結(jié)束狀態(tài)的動畫了寂纪,后羿箭從后羿位置飛到了亞瑟位置席吴。

等等,運(yùn)行怎么沒反應(yīng)呢捞蛋?動畫怎么觸發(fā)靶⒚啊?

Motion提供了三動畫觸發(fā)方法:

1)onClick標(biāo)簽拟杉,表示點(diǎn)擊場景中的某個控件來觸發(fā)動畫效果庄涡。其中有兩個屬性。
app:targetId搬设,表示要觸發(fā)動畫的視圖
app:clickAction啼染,表示點(diǎn)擊的效果,例如焕梅,toggle(循環(huán)動畫)迹鹅,transitionToStart(過渡到開始狀態(tài))
2)OnSwipe標(biāo)簽,表示通過用戶輕觸控制動畫贞言,有點(diǎn)手勢滑動的感覺
app:touchAnchorId斜棚,表示可以滑動并拖動的視圖。
app:touchAnchorSide 表示從哪邊開始拖動该窗。
app:dragDirection 表示拖動的進(jìn)度方向弟蚀。例如,dragRight表示當(dāng)向右拖動(滑動)酗失。
app:onTouchUp 表示手勢抬起的時候動作义钉。例如,stop表示手勢抬起的時候view動畫停止规肴。
3)java代碼控制.
motionLayout.transitionToEnd(),過渡動畫到結(jié)束位置捶闸。
motionLayout.setTransitionListener,監(jiān)聽動畫夜畴。

這里我們就設(shè)置點(diǎn)擊后羿觸發(fā)動畫:

<OnClick
    app:clickAction="toggle"
    app:targetId="@id/houyi" />

好了,運(yùn)行删壮,點(diǎn)擊后羿贪绘,后羿的箭成功射出去了。

但是這還不夠央碟,后羿箭到亞瑟位置肯定就會消失了税灌,怎么表示這個消失呢?用透明度亿虽,直接設(shè)置結(jié)束位置的透明度為0就會消失了菱涤。

android:alpha="0"

看看效果:



好像還是有點(diǎn)不對,箭在空中的時候就消失了洛勉,我們要的效果是射到亞瑟才消失狸窘。

這是因?yàn)樯蓜赢嫷臅r候是按照起始點(diǎn)到結(jié)束點(diǎn)過渡的流程平均分配到每個時間點(diǎn),所以他就會從一開始就慢慢線性變化透明度辩涝,直到完全消失高职。

怎么辦呢?就要用到關(guān)鍵幀KeyFrameSet了。

KeyFrameSet關(guān)鍵幀较屿,可以設(shè)定動畫過程中的某個關(guān)鍵位置或?qū)傩浴?/p>

設(shè)定關(guān)鍵幀后,MotionLayout會平滑地將視圖從起點(diǎn)移至每個中間點(diǎn)懒闷,然后移至最終目標(biāo)位置宪赶。

所以這里,我們需要設(shè)置兩個關(guān)鍵屬性:

1)快射到亞瑟的時候痒玩,箭的透明度還是1淳附。
2)射到亞瑟的時候,透明度改成0蠢古。

<KeyFrameSet>
    <KeyAttribute
        app:framePosition="98"
        app:motionTarget="@id/houyi_arrow"
        android:alpha="1" />
    <KeyAttribute
        app:framePosition="100"
        app:motionTarget="@id/houyi_arrow"
        android:alpha="0" />
</KeyFrameSet>

KeyAttribute就是設(shè)置關(guān)鍵屬性的標(biāo)簽奴曙,其中

app:framePosition 表示該關(guān)鍵幀的位置,相當(dāng)于百分比草讶。
app:motionTarget 表示作用于那個視圖

這樣設(shè)置好洽糟,后羿箭的動畫也就完成了。

瘋狂走位的亞瑟

到亞瑟了堕战,亞瑟的動畫效果是走位走位被射中坤溃。所以先設(shè)定好亞瑟的位置,從遠(yuǎn)處走到被射中的位置。

<ConstraintSet android:id="@+id/start">
    <Constraint
        android:id="@+id/houyi_arrow"
        android:layout_width="66dp"
        android:layout_height="66dp"
        android:layout_marginLeft="190dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.8">

    </Constraint>

    <Constraint
        android:id="@+id/yase"
        android:layout_width="66dp"
        android:layout_height="66dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.8"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.2">

    </Constraint>
</ConstraintSet>

<ConstraintSet android:id="@+id/end">
    <Constraint
        android:id="@+id/houyi_arrow"
        android:layout_width="66dp"
        android:layout_height="66dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.65"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.35">

    </Constraint>

    <Constraint
        android:id="@+id/yase"
        android:layout_width="66dp"
        android:layout_height="66dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.65"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.35">

    </Constraint>
</ConstraintSet>    

可以看到嘱丢,一個端點(diǎn)狀態(tài)薪介,可以放置多個控件屬性。

放好亞瑟的起始和結(jié)束狀態(tài)后越驻,再設(shè)定瘋狂走位汁政,怎么弄道偷?——KeyCycle

KeyCycle,循環(huán)關(guān)鍵幀烂完,可以給動畫添加振動试疙,其實(shí)就是波形圖,比如sin抠蚣,cos祝旷。這里我們就設(shè)定一個sin曲線給亞瑟,作為走位的路徑嘶窄。也是放到關(guān)鍵幀KeyFrameSet標(biāo)簽下怀跛。

<KeyCycle
    android:translationY="50dp"
    app:framePosition="70"
    app:motionTarget="@id/yase"
    app:wavePeriod="0.5"
    app:waveShape="sin" />

app:waveShape 表示波動類型,比如sin柄冲,cos
app:wavePeriod表示波動周期吻谋,比如0.5就表示半個sin周期,可以理解為震動0.5次现横。

好了漓拾,第一個場景搞定,看看效果:


場景二

包含控件:妲己戒祠,鐘無艷
動畫描述:從草叢走出來的妲己和鐘無艷

這一個場景主要是描述在草叢蹲伏的妲己和鐘無艷骇两,看到后羿射箭后,走出草叢準(zhǔn)備接技能姜盈。直接上代碼:

<androidx.constraintlayout.motion.widget.MotionLayout
    android:id="@+id/motionLayout2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/scene_02"
    tools:showPaths="true">


    <ImageView
        android:id="@+id/daji"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/daji_model" />

    <ImageView
        android:id="@+id/zhongwuyan"
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:src="@drawable/zhongwuyan_model" />

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

scene_02.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">

    <Transition
        app:constraintSetEnd="@+id/end"
        app:constraintSetStart="@+id/start"
        app:duration="2000">

        <OnClick
            app:clickAction="toggle"
            app:targetId="@id/daji" />
    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/daji"
            android:layout_width="80dp"
            android:layout_height="80dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.75"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.85">

        </Constraint>

        <Constraint
            android:id="@+id/zhongwuyan"
            android:layout_width="70dp"
            android:layout_height="70dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.25"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.1">

        </Constraint>
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/daji"
            android:layout_width="80dp"
            android:layout_height="80dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.65"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.65">

        </Constraint>

        <Constraint
            android:id="@+id/zhongwuyan"
            android:layout_width="70dp"
            android:layout_height="70dp"
            android:alpha="0"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.42"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.2">

        </Constraint>
    </ConstraintSet>

</MotionScene>

這里低千,我想給鐘無艷一個異形走位,就是先在草叢里走馏颂,再出來示血。

這時候就要用到另一個關(guān)鍵幀標(biāo)簽——KeyPosition

KeyPosition,表示關(guān)鍵幀的位置救拉,也就是動畫必經(jīng)的一個點(diǎn)难审。該屬性用于調(diào)整默認(rèn)的運(yùn)動路徑。

1) motion:percentX亿絮、motion:percentY指定視圖應(yīng)到達(dá)的位置剔宪。keyPositionType 屬性指定如何解釋這些值。

2) keyPositionType有三種設(shè)置

一壹无、parentRelative葱绒,相對于父視圖的位置,x為橫軸(0左-1右)斗锭,y為縱軸(0頂-1底)比如要設(shè)置位置到右端中部位置地淀,就設(shè)定app:percentY="0.5" app:percentX="1"即可。
二 岖是、deltaRelative帮毁,相對于視圖在整個運(yùn)動序列過程中移動的距離实苞,(0,0)為視圖起始位置,(1,1)為結(jié)束位置烈疚。x為橫軸黔牵,y為縱軸
三、pathRelative爷肝,x軸方向?yàn)橐晥D在路徑范圍內(nèi)移動的方向猾浦,0位視圖起始位置,1為結(jié)束位置(即x軸為起點(diǎn)和終點(diǎn)的連接線)灯抛。y軸垂直于x軸金赦,正值為路徑左側(cè),負(fù)值為右側(cè)对嚼。所以夹抗,這個和deltaRelative相比,就是x軸和Y軸的不同纵竖,相同的是都是按照起始位置到結(jié)束位置為參考漠烧。

這里我們給鐘無艷一個parentRelative。

<KeyPosition
    app:motionTarget="@id/zhongwuyan"
    app:framePosition="30"
    app:keyPositionType="parentRelative"
    app:percentY="0"
    app:percentX="0.4"
    />

最后加上兩個英雄從草叢走出來靡砌,由半透明到不透明的過程:

<KeyAttribute
    app:framePosition="0"
    app:motionTarget="@id/daji"
    android:alpha="0.7" />
<KeyAttribute
    app:framePosition="70"
    app:motionTarget="@id/daji"
    android:alpha="1" />

<KeyAttribute
    app:framePosition="0"
    app:motionTarget="@id/zhongwuyan"
    android:alpha="0.7" />
<KeyAttribute
    app:framePosition="60"
    app:motionTarget="@id/zhongwuyan"
    android:alpha="1" />

場景三

包含控件:妲己的一技能已脓,妲己的二技能,鐘無艷
動畫描述:鐘無艷閃現(xiàn)到人群中使用大招轉(zhuǎn)轉(zhuǎn)轉(zhuǎn)乏奥,妲己二技能暈眩住魯班,一技能跟上亥曹。

鐘無艷閃現(xiàn)邓了,我用的是消失再出現(xiàn)的方式,也就是改變alpha媳瞪。鐘無艷的大招骗炉,用到的是android:rotationY,設(shè)定繞y軸旋轉(zhuǎn)蛇受。

妲己的一技能和二技能都是用的普通位置移動句葵,注意控制透明度也就是出現(xiàn)和消失即可。上代碼:

scene_03.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">

    <Transition
        app:constraintSetEnd="@+id/end"
        app:constraintSetStart="@+id/start"
        app:duration="4000">

        <KeyFrameSet>

            <!-- 鐘無艷-->
            <KeyAttribute
                app:framePosition="20"
                app:motionTarget="@id/zhongwuyan2"
                android:rotationY="0" />

            <KeyAttribute
                app:framePosition="1"
                app:motionTarget="@id/zhongwuyan"
                android:alpha="1" />

            <!-- 妲己2技能-->

            <KeyPosition
                app:motionTarget="@id/daji_2"
                app:framePosition="20"
                app:keyPositionType="deltaRelative"
                app:percentY="0"
                app:percentX="0"
                />

            <KeyAttribute
                app:framePosition="20"
                app:motionTarget="@id/daji_2"
                android:alpha="1" />

            <KeyPosition
                app:motionTarget="@id/daji_2"
                app:framePosition="60"
                app:keyPositionType="deltaRelative"
                app:percentY="1"
                app:percentX="1"
                />

            <KeyAttribute
                app:framePosition="40"
                app:motionTarget="@id/daji_2"
                android:alpha="1" />

            <KeyAttribute
                app:framePosition="61"
                app:motionTarget="@id/daji_2"
                android:alpha="0" />


            <!-- 妲己1技能-->

            <KeyAttribute
                app:framePosition="55"
                app:motionTarget="@id/daji_1"
                android:alpha="1" />

            <KeyPosition
                app:motionTarget="@id/daji_1"
                app:framePosition="55"
                app:keyPositionType="deltaRelative"
                app:percentY="0"
                app:percentX="0"
                />

            <KeyAttribute
                app:framePosition="85"
                app:motionTarget="@id/daji_1"
                android:alpha="1" />

        </KeyFrameSet>

        <OnClick
            app:clickAction="toggle"
            app:targetId="@id/zhongwuyan2" />
    </Transition>

     //兢仰。乍丈。。
</MotionScene>

3把将、實(shí)際應(yīng)用場景

其實(shí)做下來可以發(fā)現(xiàn)轻专,Motionlayout實(shí)現(xiàn)動畫真的很簡便,大大提高了開發(fā)效率察蹲,這也是jetpack組件開發(fā)的初心请垛。

但是催训,Motionlayout還是有缺點(diǎn)的,比如直接通過xml代碼的情況下宗收,無法設(shè)置動畫的銜接漫拭,設(shè)定動畫的先后順序。

所以到底motionlayout應(yīng)用場景是什么呢混稽?

motionlayout作為一個過渡動畫采驻,應(yīng)該適用于一些控件切換,界面變化之類的動畫荚坞。

比如DrawerLayout挑宠,viewpager切換的時候,可以設(shè)置一些view過渡的動畫颓影。官網(wǎng)有一個類似youtube中運(yùn)動動畫的案例各淀,我這邊搬過來簡單說下。先看看效果



效果不錯吧诡挂,特別是手勢滑動的那個絲滑感碎浇,太爽了,以前做這種動畫效果少說也要半個小時吧璃俗,想想就頭疼奴璃。

現(xiàn)在,MotionLayout:so easy城豁。

來一起分析下:

包含控件:頂部布局控件topLayout(包含頂部圖片topImage苟穆,播放按鈕topPlay,關(guān)閉按鈕topClose)唱星,中部布局midlayout(包含文字部分midView)雳旅,下部菜單控件bottomView。

動畫描述(某些具體數(shù)值由代碼中得知):

一间聊、topLayout從上方依附parent位置攒盈,變化到下方bottomView的上方。高度由320dp變成54dp哎榴。
二型豁、topImage從滿鋪父布局,到最后長度不滿鋪(長度設(shè)置為高度2.5倍)尚蝌,高度距離父布局上下2dp迎变。關(guān)鍵幀:到90%進(jìn)度的時候,還是滿鋪飘言,再慢慢縮小長度氏豌。
三、topPlay热凹,topClose從不顯示(alhpa為0)到最后顯示完全(alhpa為1)泵喘。關(guān)鍵幀:到90%進(jìn)度的時候泪电,不透明還是為10%(alpha0.1),再慢慢變不透明纪铺。
四相速、midlayout,白色布局鲜锚,從底部依附父布局到bottomView的上方突诬,這個layout是為了讓toplayout下來的時候更加自然,因?yàn)閞ecycleview會變完全透明芜繁,就需要這個白色布局過渡旺隙,讓動畫更完整。
五骏令、midView蔬捷,從toplayout下方位置到最后和toplayout重合,透明度從不透明到完全透明榔袋。關(guān)鍵幀:到75%進(jìn)度的時候周拐,就完全透明。
六凰兑、bottomView妥粟,從父布局視圖下面(看不到)到父布局底部(看得見)

就這么多,分析好每個布局的起始位置吏够,結(jié)束位置锅知,再調(diào)整一下關(guān)鍵幀喉镰。一個跟隨手勢滑動的過渡動畫布局就完成了侣姆。

貼下MotionScene關(guān)鍵代碼捺宗,想看完整源代碼可以去文末附件自取蚜厉,官網(wǎng)案例和我的demo都包含昼牛。

<?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:constraintSetEnd="@+id/end"
        motion:constraintSetStart="@+id/start"
        motion:duration="1000"
        motion:motionInterpolator="linear">

        <OnSwipe
            motion:dragDirection="dragUp"
            motion:touchAnchorId="@+id/top_image_container"
            motion:touchAnchorSide="bottom" />

        <KeyFrameSet>
            <KeyPosition
                motion:curveFit="linear"
                motion:framePosition="90"
                motion:motionTarget="@id/top_image"
                motion:percentWidth="0"
                motion:percentX="0" />
            <KeyPosition
                motion:curveFit="linear"
                motion:framePosition="90"
                motion:motionTarget="@id/top_image_container"
                motion:percentWidth="0" />

            <KeyPosition
                motion:curveFit="linear"
                motion:framePosition="90"
                motion:motionTarget="@id/recyclerview_container"
                motion:percentWidth="0" />

            <KeyAttribute
                android:alpha="0"
                motion:framePosition="75"
                motion:motionTarget="@id/recyclerview_front" />

            <KeyAttribute
                android:alpha="0.10"
                motion:framePosition="90"
                motion:motionTarget="@id/image_clear" />

            <KeyAttribute
                android:alpha="0.10"
                motion:framePosition="90"
                motion:motionTarget="@id/image_play" />
        </KeyFrameSet>
    </Transition>

</MotionScene>

這里有幾個新屬性說下:

一、motion:curveFit伶椿,表示用哪種線條軌跡經(jīng)過該關(guān)鍵幀脊另,默認(rèn)是曲線(spline),更加圓滑旱捧。這是設(shè)置的linear為直線過渡廊佩,因?yàn)楸旧砭褪侵本€靖榕,所以沒什么影響茁计。
二星压、motion:percentWidth逊脯,表示視圖相對大小军洼,取值為0-1匕争,0代表初始位置寬度甘桑,1代表結(jié)束位置寬度跑杭。這里為0就代表寬度到該位置還是和初始寬度一致铆帽。
三、motion:motionInterpolator锄贼,表示動畫的插值器女阀。這里的linear就是線性運(yùn)動宅荤,還可以設(shè)置bounce彈簧運(yùn)動等等。

4冯键、關(guān)于過渡動畫

關(guān)于過渡動畫,其實(shí)之前也是存在的——TransitionManager庸汗。TransitionManager可以提供不同場景之間的過渡轉(zhuǎn)換動畫惫确,需要設(shè)定兩個場景(布局文件)蚯舱,然后兩個場景中對應(yīng)的控件id要對應(yīng)上。最后通過java代碼執(zhí)行過渡動畫陈肛。

上個代碼:

//兩個場景的布局
<FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/scene_root">

    <include layout="@layout/a_scene" />
</FrameLayout>

//場景一
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scene_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="26sp"
    android:id="@+id/text_view1"
    android:text="Text Line 1" />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="26sp"
    android:id="@+id/text_view2"
    android:text="Text Line 2" />
</LinearLayout>

//場景二
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scene_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/text_view2"
    android:textSize="22sp"
    android:text="Text Line 2" />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="22sp"
    android:id="@+id/text_view1"
    android:text="Text Line 1" />
</LinearLayout>

//獲取場景晰奖,開始場景間的動畫,從場景一變化為場景二

val sceneRoot: ViewGroup = findViewById(R.id.scene_root)
val aScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.a_scene, this)
val anotherScene: Scene = Scene.getSceneForLayout(sceneRoot, R.layout.another_scene, this)

titletv.setOnClickListener {
    TransitionManager.go(anotherScene)
}

咦,跟MotionLayout還是蠻像的蛆楞,思路也差不多溯乒,都是通過不同場景的控件完成過渡動畫。那么問題來了臊岸,既然有為什么還要出個MotionLayout呢橙数?

一尊流、前者(TransitionManager)無法設(shè)置關(guān)鍵幀帅戒,動畫只有兩個狀態(tài)。MotionLayout就可以隨意設(shè)置關(guān)鍵幀,設(shè)置不同的位置逻住,屬性等等钟哥。
二、前者不能跟隨手勢滑動瞎访,MotionLayout就絲滑的多腻贰。
三、MotionLayout全部用xml代碼就可以完成整個動畫扒秸,不需要調(diào)用一句java代碼播演。
四、前者布局控件重復(fù)太多伴奥,需要不同的xml文件写烤,寫重復(fù)的控件。

所以MotionLayout還是很優(yōu)秀的拾徙,快用起來吧洲炊!

文章來源:積木zz
鏈接:https://juejin.im/post/6856743286653386760

以下是我所整理出來的一些資料和大廠面試題,想獲取的可以點(diǎn)擊我的GitHub哦尼啡。



想獲取就點(diǎn)擊我的GitHub哦暂衡。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市崖瞭,隨后出現(xiàn)的幾起案子狂巢,更是在濱河造成了極大的恐慌,老刑警劉巖书聚,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隧膘,死亡現(xiàn)場離奇詭異,居然都是意外死亡寺惫,警方通過查閱死者的電腦和手機(jī)疹吃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來西雀,“玉大人萨驶,你說我怎么就攤上這事⊥щ龋” “怎么了腔呜?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長再悼。 經(jīng)常有香客問我核畴,道長,這世上最難降的妖魔是什么冲九? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任谤草,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘丑孩。我一直安慰自己冀宴,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布温学。 她就那樣靜靜地躺著略贮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仗岖。 梳的紋絲不亂的頭發(fā)上逃延,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機(jī)與錄音轧拄,去河邊找鬼真友。 笑死,一個胖子當(dāng)著我的面吹牛紧帕,可吹牛的內(nèi)容都是我干的盔然。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼是嗜,長吁一口氣:“原來是場噩夢啊……” “哼愈案!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鹅搪,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤站绪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后丽柿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恢准,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年甫题,在試婚紗的時候發(fā)現(xiàn)自己被綠了馁筐。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡坠非,死狀恐怖敏沉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情炎码,我是刑警寧澤盟迟,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站潦闲,受9級特大地震影響攒菠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜歉闰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一辖众、第九天 我趴在偏房一處隱蔽的房頂上張望卓起。 院中可真熱鬧,春花似錦赵辕、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至私杜,卻和暖如春蚕键,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背衰粹。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工锣光, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人铝耻。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓誊爹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瓢捉。 傳聞我的和親對象是個殘疾皇子频丘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354