在前量部分我们引入了几个示例:
- 基础使用
- 滑动处理
- 自定义属性插值
- 关键帧
在一,二部分已经大量的介绍了 MotionLayout 的功能,在这部分我们将介绍如何在已有的项目中使用 MotionLayout ,整合到已有的布局中(CoordinatorLayout, DrawerLayout, ViewPager).
在 Coordinatorlayout 中使用 MotionLayout:
( MotionLayout 可以实现类似 CoodinatorLayout 的功能,我们将在以后的文章中提供示例)
可以通过 MotionLayout 指定一部分 View 的动画,将更多有趣的动画加到已经存在的布局中。
例如,下图中的效果:
可以使用 MotionLayout 替换 AppBarLayout 中的 Toolbar , 通过 CoordinatorLayout 控制动画的进度。
尽管你可以通过 setProgress()
方法控制 MotionLayout 转换的进度,也可以创建一个子类通过监听 AppBarlayout 的偏移自动修改:
package com.google.androidstudio.motionlayoutexample.utils
import android.content.Context
import android.support.constraint.motion.MotionLayout
import android.support.design.widget.AppBarLayout
import android.util.AttributeSet
class CollapsibleToolbar @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : MotionLayout(context, attrs, defStyleAttr), AppBarLayout.OnOffsetChangedListener {
override fun onOffsetChanged(appBarLayout: AppBarLayout?, verticalOffset: Int) {
progress = -verticalOffset / appBarLayout?.totalScrollRange?.toFloat()!!
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
(parent as? AppBarLayout)?.addOnOffsetChangedListener(this)
}
}
然后在布局文件中使用:
最后我们需要实现motion_09_coordinatorlayout_header
的内容,一个 ImagerView 作为背景和一个 TextView:
创建自包含的 MotionScene
文件:
在 DrawerLayout 布局中使用 MotionLayout:
DrawerLayout 是安卓项目中一个提供侧抽屉功能的布局文件。不同于普通的 menu ,我们可以构建一个更有趣的动画:
和 CoordinatorLayout 类型我们也创建一个子类在自动的设置 MotionaLayout 的进度:
package com.google.androidstudio.motionlayoutexample.utils
import android.content.Context
import android.support.constraint.motion.MotionLayout
import android.support.v4.widget.DrawerLayout
import android.util.AttributeSet
import android.view.View
class DrawerContent @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : MotionLayout(context, attrs, defStyleAttr), DrawerLayout.DrawerListener {
override fun onDrawerStateChanged(newState: Int) {
}
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
progress = slideOffset
}
override fun onDrawerClosed(drawerView: View) {
}
override fun onDrawerOpened(drawerView: View) {
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
(parent as? DrawerLayout)?.addDrawerListener(this)
}
}
DrawerContent
将通过 onDrawerSlide
的回调slideOffset
自动设置进度,将 这个类整合进 DrawerLayout 布局中 :
motion_12_drawerlayout_content.xml
文件:
MotionScene 文件:
在 ViewPager 中使用 MotionLayout
同样我们想在 ViewPager 的头部添加更有趣的动画:
我们可以用一个小技巧来整合 ViewPager 的基础功能,创建一个子类并传入当前的位置:
package com.google.androidstudio.motionlayoutexample.utils
import android.content.Context
import android.support.constraint.motion.MotionLayout
import android.support.v4.view.ViewPager
import android.util.AttributeSet
class ViewpagerHeader @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) {
var numPages = 3
progress = (position + positionOffset) / (numPages - 1)
}
override fun onPageSelected(position: Int) {
}
}
计算很直观 — 在 onPageScrolled() 方法传入了位置,位置的变化从0到2,一共有三个界面。所以进度的计算应该是: progress = (position + positionOffset) / (numPages-1)
结合 MotionLayout 和 Lottie
前面的示例使用多个 ImageView 实现动画。也可以通过使用 Lottie 文件整合进 MotionLayout 中直接设置进度。让我们使用 LottieAnimationView 替换之前的示例:
布局文件:
MotionScene 中关键参数是 motion:progress
:
因为 LottieAnimationView 存在 setProgress() 方法,所以我们可以在 MotionLayout 中调用它来控制 Lottie 的进度。 完整的 MotionScene 文件: