我在以前翻译的一篇文章中介绍了MotionLayout,若是你还不知道MotionLayout是什么,先看这篇MotionLayout介绍android
今天想要介绍一个用MotionLayout实现的很是炫酷的翻页动画,翻译自Mediumgit
这是效果github
如何实现上面的卡片呢app
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motionLayout"
app:layoutDescription="@xml/memory_curve_scene"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:motionDebug="SHOW_ALL">
<FrameLayout
android:id="@+id/bottomCard"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/design_default_color_primary">
</FrameLayout>
</androidx.constraintlayout.motion.widget.MotionLayout>
复制代码
注意一下这一行app:motionDebug=”SHOW_ALL”
,它可让咱们在屏幕上展现一些当前MotionLayout的一些属性,好比progress等等。一般只会在debug模式下使用,记得app正式发布的时候关闭它。ide
而后在MotionScene文件,也就是咱们在res/xml
目录下定义的文件中加入初始的ConstraintSetpost
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ConstraintSet android:id="@+id/rest">
<Constraint
android:id="@id/topCard"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="50dp"
android:layout_marginTop="50dp"
android:layout_marginEnd="50dp"
android:layout_marginBottom="50dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
</ConstraintSet>
</MotionScene>
复制代码
让咱们添加pass
和like
状态的constraintSet,当咱们彻底滑动到左边或者右边的时候,就处在这个状态。动画
<ConstraintSet android:id="@+id/pass"
app:deriveConstraintsFrom="@id/rest">
<Constraint
android:id="@id/topCard"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="50dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="200dp"
android:layout_marginBottom="80dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintWidth_percent="0.7"/>
</ConstraintSet>
<ConstraintSet android:id="@+id/like"
app:deriveConstraintsFrom="@id/rest">
<Constraint
android:id="@id/topCard"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="200dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="50dp"
android:layout_marginBottom="80dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_percent="0.7"/>
</ConstraintSet>
复制代码
pass
和like
状态其实就是镜像的两个状态。spa
注意一下这一行app:deriveConstraintsFrom="@id/rest"
,这能让该ConstraintSet自动继承另外一个ConstraintSet的属性,固然也能够覆写另外一个ConstraintSet的属性。翻译
如今,咱们有了三个ConstraintSet,分别是rest
,like
和pass
。如今咱们须要让一个状态以点击或者滑动的方式过渡debug
咱们加入了<OnSwipe>
<Transition
app:constraintSetEnd="@+id/pass"
app:constraintSetStart="@+id/rest"
app:duration="300" >
<OnSwipe
app:dragDirection="dragLeft"
app:onTouchUp="autoComplete"
app:touchAnchorId="@id/topCard"
app:touchAnchorSide="left"
app:touchRegionId="@id/topCard" />
</Transition>
复制代码
like
部分是镜像的
如今咱们能够这样
为了使卡片飞出屏幕,咱们还须要添加两个ConstraintSet:offscreenLike
和offscreenPass
<ConstraintSet android:id="@+id/offscreenLike"
app:deriveConstraintsFrom="@id/like">
<Constraint
android:id="@id/topCard"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginBottom="80dp"
android:layout_marginEnd="50dp"
android:layout_marginTop="20dp"
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintWidth_percent="0.7" />
</ConstraintSet>
复制代码
咱们想何时卡片飞出屏幕呢?当卡片处于like
阶段或者pass
的时候。
所以,咱们加入Transition
<Transition
app:autoTransition="animateToEnd"
app:constraintSetEnd="@+id/offscreenLike"
app:constraintSetStart="@+id/like"
app:duration="150" />
复制代码
咱们如今须要在layout中添加咱们的底部卡片。
<FrameLayout
android:id="@+id/topCard"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/cardview_shadow_start_color">
</FrameLayout>
复制代码
在res/xml
的MotionScene中,咱们须要更改每一个ConstraintSet
<ConstraintSet android:id="@id/rest">
<!-- ... -->
<Constraint android:id="@id/bottomCard">
<Layout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="50dp"
android:layout_marginEnd="50dp"
android:layout_marginStart="50dp"
android:layout_marginTop="50dp" />
<Transform
android:scaleX="0.90"
android:scaleY="0.90" />
</Constraint>
</ConstraintSet>
<ConstraintSet
android:id="@+id/offScreenLike"
app:deriveConstraintsFrom="@id/like">
<!-- ... -->
<Constraint android:id="@id/bottomCard">
<Transform
android:scaleX="1"
android:scaleY="1" />
</Constraint>
</ConstraintSet>
复制代码
咱们须要手动添加代码来让卡片滑动到offscreenLike
阶段的时候,重置回rest
阶段
private fun setInfinite() {
motionLayout.setTransitionListener(object : TransitionAdapter() {
override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
when (currentId) {
R.id.offscreenLike, R.id.offscreenPass -> {
motionLayout?.progress = 0f
motionLayout?.setTransition(R.id.rest, R.id.like)
}
}
}
})
}
复制代码
咱们最后再在xml中添加两个View
<ImageView
android:id="@+id/likeIcon"
android:src="@drawable/ic_baseline_favorite_border"
android:tint="#fbc02d"
android:background="@drawable/backround_circle"
android:layout_height="0dp"
android:layout_width="0dp" />
复制代码
,而后更改MotionScene中相应的ConstraintSet,
<ConstraintSet android:id="@+id/like"
app:deriveConstraintsFrom="@id/rest">
..........
<Constraint android:id="@+id/likeIcon">
<Layout
android:layout_width="100dp"
android:layout_height="100dp"
app:layout_constraintBottom_toBottomOf="@id/topCard"
app:layout_constraintEnd_toEndOf="@id/topCard"
app:layout_constraintStart_toStartOf="@id/topCard"
app:layout_constraintTop_toTopOf="@id/topCard" />
<Transform
android:scaleX="1"
android:scaleY="1" />
<PropertySet android:alpha="1" />
</Constraint>
复制代码
以及
<ConstraintSet android:id="@+id/rest">
.....................
<Constraint android:id="@+id/likeIcon">
<Layout
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Transform
android:scaleX="0.5"
android:scaleY="0.5" />
<PropertySet android:alpha="0" />
</Constraint>
复制代码
这样,就实现了咱们想要的效果
最后附上github项目地址,其中用到了这个动画
参考:Medium