前言
在平时的开发中,我们往往需要做一些页面、布局相关的切换效果,以前写过一篇转场相关的动画的文章juejin.cn/post/719956…
但这是比较重量级,有时候我们做fragment切换或者一些控件切换做衔接动画,想要比较方便的实现,其实ViewPager就提供了切换动画的方法,而且使用起来也十分的方便,扩展性还很不错,简单来说就是你可以用简单的方式去实现你自定义的控件切换效果。
1. 使用方式
使用非常简单
viewpager.setPageTransformer(CardPageTransformer())
直接调用viewpager的setPageTransformer方法,传一个PageTransformer,而这个PageTransformer需要我们自定义,具体实现切换动画效果的地方也是在这里面
在transformPage方法中写具体的动画效果
2. 部分动画效果
为了方便使用,官方也已经提供一些基础的动画效果给开发者使用
可以参考developer.android.google.cn/develop/ui/…
如果你要实现的效果是在里面的,你可以直接拷贝它的代码来使用,这是最方便的方法。
当然,除了使用官方列举出的一些基础效果之外,你还可以定义自己的效果。我们可以来看看一个卡片切换的效果,代码就是上面的使用列举的demo
class CardPageTransformer : ViewPager2.PageTransformer {
var mScaleOffset = 200f
var mTranslationOffset = 100f
override fun transformPage(page: View, position: Float) {
if (position <= 0f) {
page.translationX = 0f
} else {
val pageWidth: Int = page.width
val transX = -pageWidth * position + mTranslationOffset * position
page.translationX = transX
val scale: Float = (pageWidth - mScaleOffset * position) / pageWidth.toFloat()
page.scaleX = scale
page.scaleY = scale
page.translationZ = -position
}
}
}
可以看看效果
我们也可以用另外一种方式更直观的去实现
class DepthPageTransformer : ViewPager2.PageTransformer {
private val MIN_SCALE = 0.75f
override fun transformPage(page: View, position: Float) {
page.apply {
val pageWidth = width
when {
position < -1 -> {
alpha = 0f
}
position <= 0 -> {
alpha = 1f
translationX = 0f
translationZ = 0f
scaleX = 1f
scaleY = 1f
}
position <= 1 -> {
alpha = 1 - position
translationX = pageWidth * -position
translationZ = -1f
val scaleFactor = (MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position)))
scaleX = scaleFactor
scaleY = scaleFactor
}
else -> {
alpha = 0f
}
}
}
}
}
看看效果
可以看到两个的效果差不多,但是第二个demo写了if-else判断会比较好理解一点。
2. transformPage方法
上面说了,自定义切换动画效果的方法就是用transformPage,该方法有两个参数,View类型的page和Float类型的position
上面的第二个Demo可以看出,它是根据position的4个不同的区间做操作。那么这个pager是什么,position又是什么呢?
我们可以去看接口的说明
嗯~ 看完之后还是有点懵,没事,我们可以写个空的PageTransformer然后加打印看看这个切换的过程
class EmptyPageTransformer : ViewPager2.PageTransformer {
override fun transformPage(page: View, position: Float) {
Log.v("mmp","==== ${page.tag} ${position}")
}
}
PS:我给每个view设置了不同的tag,方便打印
从页面1切换到页面2的过程可以看到
其实看这个打印是不是已经很明显了,你能看到这个过程有两个view都有回调到这个方法,一眼你就能理解是切换的两个view吗,而tag为0的view的position是从0到-1,tag为1的view的position是从1到1。
那从这里你就能很明显的得到这些信息,这个过程涉及两个控件,所以要有个View类型的page字段表示当前操作的是哪个控件。position是用float类型表示的进度。除此之外,你还能发现一个属性“方向”,从0-1是左滑,从1-0是右滑。
所以在上面的操作之后,如果再进行左滑,你可以大胆的推测,tag为0的view的position会从-1到0,tag为1的view的position会从0到1。我们可以看看是不是这样
可以看到结果正如我们预料的那样。
3. 开始自定义动画
知道了transformPage的参数的含义之后,我们就能非常方便的实现我们自定义的切换动画效果。当然这个过程需要一定的想象力。
通过进度position,去逐渐改变view的一些属性(alpha、translation等等),这是不是瞬间就有点属性动画的意思了
刚开始不熟的话,我们可以按照第二个Demo那样子给position去分区间判断,就不容易混乱。
可以试着随便写一个旋转效果(一般这种横向切换也不会做旋转效果)
class NewPageTransformer : ViewPager2.PageTransformer {
override fun transformPage(page: View, position: Float) {
page.apply {
pivotY = (page.height / 2).toFloat()
pivotX = (page.width / 2).toFloat()
val w = width
when {
position < -1 -> {
}
position <= 0 -> {
rotation = -90 * position
translationX = -w * position
}
position <= 1 -> {
rotation = -90 * position
translationX = w * position
}
else -> {
}
}
}
}
}
可以看看效果
一般也不会做这种奇怪的效果,这里只是为了方便演示