本文介绍如何在现有的应用程序使用MotionLayout,它在现有的布局,如CoordinatorLayout,DrawerLayout或ViewPager整合。
请注意,MotionLayout可用于实现与CoordinatorLayout类似的行为。我们将在即将发表的文章中展示此示例)
利用MotionLayout的一种简单方法是使用它来指定屏幕内容的某些部分可以如何设置动画。这样,您可以向已在应用程序中设置的现有布局/屏幕添加更多有趣的动作,而无需从头开始。
例如,您可能想要构建以下屏幕:
图片超过csdn限制
这里的一般想法是用MotionLayout替换AppBarLayout中的Toolbar元素。然后我们让CoordinatorLayout驱动动画的进度。
由于您可以通过调用来控制MotionLayout的过渡位置setProgress(),因此我们可以通过监听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)
}
}
然后可以修改您的CoordinatorLayout XML文件以使用此子类而不是工具栏:
motion_09_coordinatorlayout.xml
剩下要做的就是创建一个包含我们想要动画的视图的MotionLayout文件。这里我们有一个ImageView作为背景和TextView:
最后,动画本身可以在MotionScene中描述:
scene_09.xml
DrawerLayout是Android框架提供的另一个类,用于显示侧抽屉。我们可能想要构建一些更有趣的东西,而不是通常的菜单:
图片过大超过csdn限制
与我们将MotionLayout与CoordinatorLayout / AppBarLayout集成的方法类似,我们可以构建一个自动设置MotionLayout进度的子类:
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)
}
}
此子类将从回调中自动设置给定slideOffset值的进度onDrawerSlide()。
使用这个子类,我们可以轻松地在DrawerLayout中集成MotionLayout:
motion_13_drawerlayout.xml
该motion_12_drawerlayout_content.xml文件只包含与我们之前的CoordinatorLayout示例中使用的布局类似的布局。
菜单文件是使用MotionLayout(或者更确切地说,我们创建的DrawerContent子类)的文件:
motion_13_drawerlayout_menu.xml
MotionScene文件只是旋转不同的元素(检查和ConstraintSet rotation之间的属性):startend
scene_13_menu.xml
以类似的方式,我们可能希望有一个比典型的更有趣的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,1或2,因为我们有3页),positionOffset(从0到1,偏离位置…)。然后可以将动画的总进度设置为:
progress = (position + positionOffset) / (numPages-1)
前面的示例使用实际的ImageViews构建了一个简单的动画标题。您还可以在MotionLayout中轻松集成Lottie文件,并直接设置进度 - MotionLayout将能够驱动它。
让我们改变前面的例子,改为使用LottieAnimationView:
为简单起见,让我们将基于MotionLayout的ViewPager标头的布局文件替换为仅包含LottieAnimationView:
MotionScene中的关键修改是使用以下motion:progress属性:
由于LottieAnimationView有一个setProgress()函数,这将导致MotionLayout调用它,并允许您直接驱动Lottie进度。
完整的MotionScene文件可以写成:
scene_23.xml
文章介绍了如何在现有布局中轻松集成MotionLayout。
文章代码