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哦暂衡。