当前位置:网站首页>一看就会 MotionLayout使用的几种方式
一看就会 MotionLayout使用的几种方式
2022-06-28 05:23:00 【码中之牛】
作者:newki
转载地址:https://juejin.cn/post/7110027299214999589
MotionLayout效果实现的几种方式
MotionLayout 的使用大家应该都会了,如果不会看这里。
本文就不科普如何使用,什么属性是什么意思,怎么使用之类的了,这里只是探讨一下 MotionLayout 效果实现的几种方式。
一、ConstraintLayout 的方式定义
我们知道 MotionLayout 是 ConstraintLayout 库中的功能,我们可以直接使用 ConstraintLayout 来定义两组不同的 ConstraintLayout 布局,使用 ConstraintSet 来切换不同的布局。
原始布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/constraint_parent" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorPrimary" app:layout_constraintVertical_bias="0.3">
<TextView android:id="@+id/view_2" android:layout_width="200dp" android:layout_height="wrap_content" android:background="@android:color/white" android:padding="16dp" app:layout_constraintBottom_toBottomOf="@id/view_1" app:layout_constraintEnd_toEndOf="@id/view_1" app:layout_constraintStart_toStartOf="@id/view_1" />
<androidx.appcompat.widget.AppCompatImageView android:id="@+id/view_1" android:layout_width="200dp" android:layout_height="170dp" android:background="@color/colorAccent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageView android:id="@+id/icon" android:layout_width="32dp" android:layout_height="32dp" android:layout_margin="16dp" android:src="@mipmap/ic_launcher_round" app:layout_constraintBottom_toBottomOf="@id/view_1" app:layout_constraintEnd_toEndOf="@id/view_1" app:layout_constraintTop_toTopOf="@id/view_1" />
<View android:id="@+id/bottom" android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/colorAccent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
改变后的布局:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:background="@color/colorPrimary" app:layout_constraintVertical_bias="0.3" android:layout_height="match_parent">
<TextView android:id="@+id/view_2" app:layout_constraintStart_toStartOf="@id/view_1" app:layout_constraintEnd_toEndOf="@id/view_1" android:layout_width="200dp" android:background="@android:color/white" android:padding="16dp" app:layout_constraintTop_toBottomOf="@id/view_1" android:layout_height="wrap_content" />
<androidx.appcompat.widget.AppCompatImageView android:layout_width="200dp" android:layout_height="150dp" android:id="@+id/view_1" android:background="@color/colorAccent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent"/>
<androidx.appcompat.widget.AppCompatImageView android:layout_width="32dp" android:src="@mipmap/ic_launcher_round" android:id="@+id/icon" app:layout_constraintEnd_toEndOf="@id/view_1" app:layout_constraintTop_toBottomOf="@id/view_1" app:layout_constraintBottom_toBottomOf="@id/view_1" android:layout_margin="16dp" android:layout_height="32dp"/>
<View android:layout_width="match_parent" android:layout_height="50dp" android:id="@+id/bottom" app:layout_constraintTop_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" android:background="@color/colorAccent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
使用的时候:
val raw = ConstraintSet().apply {
this.clone([email protected], R.layout.activity_demo13_java)
}
val detail = ConstraintSet().apply {
this.clone([email protected], R.layout.activity_demo13_java_transform)
}
val constraintLayout = findViewById<ConstraintLayout>(R.id.constraint_parent)
constraintLayout.click {
val constraintSet = if (toggle) detail else raw
TransitionManager.beginDelayedTransition(constraintLayout)
constraintSet.applyTo(constraintLayout)
toggle = !toggle
}
效果:

需要注意的是这里的View的数量和Id需要一 一对 应 哦!
二、MotionLayout Xml 的方式定义
也就是默认的定义,最为普遍的方式,在之前的文章中有一些复杂的定义方式。
这里就以一个简单的Demo说下如何使用:
<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:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" app:layoutDescription="@xml/activity_demo13_xml_scene" app:showPaths="true">
<View android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/colorAccent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
定义的场景xml:
<?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">
<!-- 只能设置一些Constraint布局的一些专用属性 用于位置变换 -->
<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">
<!-- 可以设置自定义的属性 -->
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#D81B60" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/button" android:layout_width="34dp" android:layout_height="34dp" android:layout_marginEnd="8dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="parent">
<!-- 可以设置自定义的属性 -->
<CustomAttribute motion:attributeName="backgroundColor" motion:customColorValue="#9999FF" />
</Constraint>
</ConstraintSet>
<Transition motion:constraintSetEnd="@+id/end" motion:constraintSetStart="@+id/start" motion:duration="1000" motion:motionInterpolator="linear">
<!-- 点击 -->
<OnClick motion:clickAction="toggle" motion:targetId="@+id/button" />
<KeyFrameSet>
<KeyAttribute android:rotation="-45" android:scaleX="2" android:scaleY="2" motion:framePosition="40" motion:motionTarget="@+id/button" />
<KeyPosition motion:framePosition="70" motion:keyPositionType="parentRelative" motion:motionTarget="@+id/button" motion:percentY="0.25" />
</KeyFrameSet>
</Transition>
</MotionScene>
效果:

场景内部的设置涉及到关键帧位置与关键帧属性的配置,代码中都有详细的注释,大家留意即可!
三、MotionLayout 配合 AppbarLayout
封装一个自己的 MotionLayout,当 AppbarLayout 滚动的过程中监听它的完成度,设置 MotionLayout 的Progress。
自定义MotionLayout:
class MyAppbarMotionLayout @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : MotionLayout(context, attrs, defStyleAttr), AppBarLayout.OnOffsetChangedListener {
override fun onOffsetChanged(appBarLayout: AppBarLayout?, verticalOffset: Int) {
val progressVal = -verticalOffset / appBarLayout?.totalScrollRange?.toFloat()!!
YYLogUtils.w("progress:$progressVal")
progress = progressVal
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
(parent as? AppBarLayout)?.addOnOffsetChangedListener(this)
}
}
使用:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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" android:background="@color/white" android:orientation="vertical">
<com.guadou.lib_baselib.view.titlebar.EasyTitleBar android:layout_width="match_parent" android:layout_height="wrap_content" app:Easy_title="协同AppbarLayout" />
<androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="wrap_content">
<com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:orientation="vertical" app:elevation="0dp">
<com.guadou.kt_demo.demo.demo13_motionlayout.view.MyAppbarMotionLayout android:id="@+id/motionLayout" android:layout_width="match_parent" android:layout_height="200dp" android:minHeight="50dp" app:layoutDescription="@xml/scene_13_appbar" app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed">
<ImageView android:id="@+id/background" android:layout_width="match_parent" android:layout_height="200dp" android:scaleType="centerCrop" android:src="@drawable/chengxiao" />
<TextView android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cheng Xiao" android:textColor="#FFFFFF" android:textSize="25dp" android:transformPivotX="0dp" android:transformPivotY="0dp" />
</com.guadou.kt_demo.demo.demo13_motionlayout.view.MyAppbarMotionLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_behavior="@string/appbar_scrolling_view_behavior">
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/scroll_content" />
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</LinearLayout>
定义的场景:
<?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" />
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/background" android:layout_width="match_parent" android:layout_height="200dp" android:alpha="1.0" motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:rotation="-90.0" motion:layout_constraintBottom_toBottomOf="@+id/background" motion:layout_constraintLeft_toLeftOf="@id/background">
<CustomAttribute motion:attributeName="textSize" motion:customFloatValue="25" />
<CustomAttribute motion:attributeName="textColor" motion:customColorValue="@color/white" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/background" android:layout_width="match_parent" android:layout_height="50dp" android:alpha="0.7" motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginBottom="8dp" android:rotation="0.0" motion:layout_constraintBottom_toBottomOf="@+id/background" motion:layout_constraintLeft_toLeftOf="@id/background" motion:layout_constraintRight_toRightOf="@id/background" motion:layout_constraintTop_toTopOf="@id/background">
<CustomAttribute motion:attributeName="textSize" motion:customFloatValue="18" />
<CustomAttribute motion:attributeName="textColor" motion:customColorValue="@color/black" />
</Constraint>
</ConstraintSet>
</MotionScene>
这样就能实现MotionLayout 跟随 AppbarLayout的滚动做对应滚动了。
效果:

四、MotionLayout 配合 ViewPager
这样的效果和 AppbarLayout 的情况类似,当ViewPager滚动页面的时候,顶部的MotionLayout做对应的动画。
自定义MotionLayout:
class MyViewpagerMotionLayout @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : MotionLayout(context, attrs, defStyleAttr), ViewPager.OnPageChangeListener {
override fun onPageScrollStateChanged(state: Int) {
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
val numPages = 3
progress = (position + positionOffset) / (numPages - 1)
}
override fun onPageSelected(position: Int) {
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
val viewGroup = (parent as? ViewGroup)!!
for (i in 0 until viewGroup.childCount) {
val view = viewGroup.getChildAt(i)
if (view is ViewPager) {
view.addOnPageChangeListener(this)
break
}
}
}
}
使用的xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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" android:background="@color/white" android:orientation="vertical">
<com.guadou.lib_baselib.view.titlebar.EasyTitleBar android:layout_width="match_parent" android:layout_height="wrap_content" app:Easy_title="协同AppbarLayout" />
<com.guadou.kt_demo.demo.demo13_motionlayout.view.MyViewpagerMotionLayout android:id="@+id/motionLayout" android:layout_width="match_parent" android:layout_height="200dp" app:layoutDescription="@xml/scene_13_viewpager">
<ImageView android:id="@+id/background" android:layout_width="match_parent" android:layout_height="200dp" android:scaleType="centerCrop" android:src="@drawable/chengxiao" />
<TextView android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cheng Xiao" android:textColor="#FFFFFF" android:textSize="25dp" />
</com.guadou.kt_demo.demo.demo13_motionlayout.view.MyViewpagerMotionLayout>
<androidx.viewpager.widget.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent">
</androidx.viewpager.widget.ViewPager>
</LinearLayout>
场景的xml:
<?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" />
<KeyFrameSet>
<KeyAttribute motion:framePosition="50" motion:motionTarget="@id/label" >
<CustomAttribute motion:attributeName="textSize" motion:customFloatValue="15" />
<CustomAttribute motion:attributeName="textColor" motion:customColorValue="@android:color/holo_blue_light" />
</KeyAttribute>
<KeyPosition motion:framePosition="50" motion:keyPositionType="parentRelative" motion:motionTarget="@id/label" motion:percentY="0.15" />
</KeyFrameSet>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/background" android:layout_width="match_parent" android:layout_height="200dp" android:alpha="1.0" motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" motion:layout_constraintBottom_toBottomOf="@+id/background" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintStart_toStartOf="parent" motion:layout_constraintTop_toTopOf="@id/background">
<CustomAttribute motion:attributeName="textSize" motion:customFloatValue="25" />
<CustomAttribute motion:attributeName="textColor" motion:customColorValue="@color/white" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/background" android:layout_width="match_parent" android:layout_height="200dp" android:alpha="1.0" motion:layout_constraintBottom_toBottomOf="parent" />
<Constraint android:id="@+id/label" android:layout_width="wrap_content" android:layout_height="wrap_content" motion:layout_constraintBottom_toBottomOf="@+id/background" motion:layout_constraintRight_toRightOf="parent" motion:layout_constraintEnd_toEndOf="parent" motion:layout_constraintTop_toTopOf="@id/background">
<CustomAttribute motion:attributeName="textSize" motion:customFloatValue="25" />
<CustomAttribute motion:attributeName="textColor" motion:customColorValue="@android:color/holo_red_dark" />
</Constraint>
</ConstraintSet>
</MotionScene>
当ViewPager滚动的时候,设置 MotionLayout 的 progress 。
效果:

此效果的场景内部的设置涉及到关键帧位置与关键帧属性的配置,关键帧属性内又定义了自定义属性,大家留意!
总结
MotionLayout 可以 配合的控件很多,这里只是列出了常用的一些控件,它还能配合DrawerLayout TabLayout等。本质都是监听事件,改变 MotionLayout 的 Progress 值。
结合这几种常用的方式,我们就能完成大部分的页面动画效果了!
边栏推荐
- Operation of 2022 power cable judgment question simulation examination platform
- Oracle基础知识总结
- Determine whether an attribute exists in an object
- Jdbc的使用
- 線條動畫
- Quartus replication IP core
- 2022 special operation certificate examination question bank and simulation examination for safety management personnel of fireworks and firecrackers business units
- Informatics Orsay all in one 1360: strange lift
- JS中的链表(含leetcode例题)<持续更新~>
- Extjs library management system source code intelligent library management system source code
猜你喜欢

A guide to P2P network penetration (stun) for metartc5.0 programming

Deeplearning ai-week1-quiz

Shutter nestedscrollview sliding folding head pull-down refresh effect

Gorm transaction experience

Sharing | intelligent environmental protection - ecological civilization informatization solution (PDF attached)

Why is point shield cloud forced to quit playing?

北斗三号短报文终端在大坝安全监测方案的应用

The heading angle of sliceplane is the same as that of math Corresponding transformation relation of atan2 (y, x)

Dart learning - functions, classes

Store inventory management system source code
随机推荐
Biovendor sRAGE protein solution
指定默认参数值 仍报错:error: the following arguments are required:
北斗三号短报文终端在大坝安全监测方案的应用
Extjs library management system source code intelligent library management system source code
MCLK configuration of Qualcomm platform camera
Line animation
如何做好水库大坝安全监测工作
8VC Venture Cup 2017 - Elimination Round D. PolandBall and Polygon
【JVM】——JVM中內存劃分
MySQL export database dictionary to excel file
电子邮件营销的优势在哪里?为什么shopline独立站卖家如此重视?
Interpretation of cloud native microservice technology trend
Zzuli:1072 frog climbing well
jsp连接Oracle实现登录注册
Unity out ref params
拉萨手风琴
How to develop the language pack in the one-to-one video chat source code
CSCI GA scheduling design
How does guotaijun charge for safe varieties? Let's talk about the futures account opening process
博客登录框