GuideBackgroundColorAnimation 详解:ViewPager 滑动时背景色渐变
很多 App 的引导页(新手引导/功能介绍)有个"高级感"效果:用户在 ViewPager 上左右滑动切换页面时,整个背景颜色会随着滑动进度平滑过渡——从蓝色渐变到橙色,再从橙色渐变到紫色,像调色盘一样丝滑。这个效果就是 GuideBackgroundColorAnimation 要做的事。虽然库不大(2014 年发布、642 Star),但它展示的"用 ArgbEvaluator + ViewPager 滑动偏移做颜色插值"技巧,至今仍是实现此类效果的通用方案。本文讲清它是什么、原理怎么实现、怎么自己手搓。
GitHub 仓库:RonanCN/GuideBackgroundColorAnimation(642 Star)。
1、它是什么
GuideBackgroundColorAnimation 是一个 Android 引导页背景色渐变库,效果是:ViewPager 左右滑动时,背景颜色跟随滑动偏移量(positionOffset)做线性插值过渡。描述原文是"A library for making the background color change while you scroll the viewpager"——一句话概括了核心。
// 核心定位
GuideBackgroundColorAnimation = ViewPager 滑动时背景色平滑渐变
// 基本面
// 作者:RonanCN(fork 自 TaurusXi 的原始实现)
// 语言:Java(Android Studio 项目)
// 星标:642 Star
// 许可:Apache 2.0
// 创建:2014 年(经典老库,但原理永不过时)
// 典型场景
// 引导页/新手引导:3~5 页滑动介绍,每页配一个主题色,滑动时颜色渐变过渡2、核心原理:ArgbEvaluator + positionOffset
这个效果的实现思路非常精巧,核心就两个要素:
// 要素一:ViewPager.OnPageChangeListener 的 positionOffset
// 滑动过程中,positionOffset 从 0 连续变到 1(表示"滑动了多少比例")
// 例如从第0页滑向第1页,positionOffset 从 0 → 0.1 → 0.5 → 0.9 → 1.0
// 要素二:ArgbEvaluator 做颜色插值
// ArgbEvaluator.getInstance().evaluate(fraction, color0, color1)
// fraction=0 时返回 color0,fraction=1 时返回 color1
// 中间值返回两者的渐变插值色(RGB 各通道线性插值)
// 组合:positionOffset 就是 fraction!
// 背景色 = ArgbEvaluator.evaluate(positionOffset, 当前页颜色, 下一页颜色)
// → 滑动到一半时,背景就是两页颜色的 50% 混合色就这么简单——ViewPager 的滑动偏移量天然就是一个 0~1 的"进度百分比",而 ArgbEvaluator 天然就是"按百分比在两个颜色间插值"的工具。两者一拼,效果就成了。这个思路不仅适用于背景色——任何"随滑动进度变化的属性"(透明度、缩放、旋转)都可以用同样的 positionOffset 驱动。
3、手搓实现:完整代码
// 核心:自定义 ViewPager.OnPageChangeListener
class GuidePageListener(
private val rootView: View, // 要改背景色的 View
private val colors: IntArray // 每页对应的背景色
) : ViewPager.OnPageChangeListener {
override fun onPageScrolled(
position: Int, positionOffset: Float, positionOffsetPixels: Int
) {
// 关键:根据 position 和 positionOffset 算出当前混合色
val color = if (position < colors.size - 1) {
// 还在可过渡范围内:在 当前页颜色 与 下一页颜色 之间插值
ArgbEvaluator.getInstance().evaluate(
positionOffset,
colors[position],
colors[position + 1]
) as Int
} else {
// 已到最后一页,用最后的颜色
colors[colors.size - 1]
}
rootView.setBackgroundColor(color)
}
override fun onPageSelected(position: Int) {}
override fun onPageScrollStateChanged(state: Int) {}
}
// 使用
val colors = intArrayOf(
Color.parseColor("#2196F3"), // 第0页:蓝
Color.parseColor("#FF9800"), // 第1页:橙
Color.parseColor("#9C27B0") // 第2页:紫
)
viewPager.addOnPageChangeListener(GuidePageListener(rootLayout, colors))整个实现不到 30 行核心代码,但效果非常"高级"。这就是"好思路 > 多代码"的典型案例——不是代码量大才厉害,而是用最少的代码、最直接的思路解决问题。ArgbEvaluator 是 Android API 自带的(API 1+),ViewPager 的 positionOffset 也是自带回调,这个库的贡献在于把两者组合到了一起,形成了一个可复用的模式。
4、ArgbEvaluator 深入:颜色插值的原理
ArgbEvaluator 为什么能做出"丝滑渐变"?它内部做的事其实很简单——对颜色的 A/R/G/B 四个通道分别做线性插值:
// ArgbEvaluator.evaluate(fraction, startColor, endColor) 的内部逻辑
// 假设 fraction = 0.5(滑动到一半)
// startColor = #2196F3 (ARGB: FF 21 96 F3)
// endColor = #FF9800 (ARGB: FF FF 98 00)
// 逐通道线性插值:
// A: FF 与 FF → FF(不变)
// R: 21 与 FF → 0x90(中点)
// G: 96 与 98 → 0x97(几乎不变)
// B: F3 与 00 → 0x79(中点)
// 结果:#909779(蓝橙过渡的中间色,偏灰绿)
// 这就是"渐变"的本质:不是"切换颜色",而是"逐通道慢慢挪过去"
// 因为每个通道都在连续变化,所以视觉上是丝滑过渡而非跳变- ArgBEvaluator 特别适合颜色插值,因为它考虑了"颜色空间的感知均匀性"——直接对 RGB 线性插值在中间会偏灰,ArgbEvaluator 做了优化让过渡更自然
5、扩展:不止背景色
掌握了"用 positionOffset 驱动属性变化"这个模式,你能做的远不止背景色渐变:
// 模式:onPageScrolled(position, positionOffset, ...) 里
// 用 positionOffset 做任何 0~1 的属性插值
// ① 图标缩放:当前页图标大,旁边的缩小
val scale = 1f - positionOffset * 0.3f // 滑动时缩小到 0.7
icon.scaleX = scale
icon.scaleY = scale
// ② 透明度过渡:旧页淡出、新页淡入
imageView.alpha = 1f - positionOffset
// ③ 平移:标题随滑动从右滑入
title.translationX = positionOffset * screenWidth
// ④ 多色渐变文字(配合 Titanic 的 Shader 技巧)
// 用 positionOffset 控制 shader 的颜色混合
// 核心:positionOffset 就是你的"万能动画进度条"很多"引导页酷炫动画"开源库,底层都是这个套路——监听 ViewPager 滑动、拿 positionOffset、驱动各种属性。GuideBackgroundColorAnimation 是其中最简洁的一个(只驱动背景色),但它的原理是所有同类效果的母版。
6、在 ViewPager2 上的迁移
// ViewPager2 的回调名不同,但 positionOffset 概念完全一致
viewPager2.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageScrolled(
position: Int, positionOffset: Float, positionOffsetPixels: Int
) {
// 和 ViewPager 一模一样的逻辑
val color = if (position < colors.size - 1) {
ArgbEvaluator.getInstance().evaluate(
positionOffset, colors[position], colors[position + 1]
) as Int
} else {
colors.last()
}
rootLayout.setBackgroundColor(color)
}
})- ViewPager2 的回调类名从 OnPageChangeListener 变为 OnPageChangeCallback,但 position / positionOffset 参数完全一致,迁移成本几乎为零
7、使用方式与集成
// 方式一:直接拷贝核心代码(推荐)
// 核心就是上面第3节的 GuidePageListener,不到30行
// 不需要引入整个库,直接拷进项目即可
// 方式二:clone 源码参考
// git clone https://github.com/RonanCN/GuideBackgroundColorAnimation
// 核心类在 library/ 目录下
// 注意事项
// - 库较老(2014-2015),使用 support 库的 ViewPager
// - 新项目用 ViewPager2 + AndroidX,核心逻辑完全相同
// - 建议直接用手搓版(第3节代码),不依赖旧库8、最佳实践与同类效果
- 引导页选色:相邻两页的颜色"色距"别太大(如蓝→橙→紫可以,但红→绿→蓝太跳),过渡更自然
- 性能:onPageScrolled 高频回调,setBackgroundColor 很轻量,不需要额外优化
- 进阶:把 setBackgroundColor 换成 GradientDrawable + setColors,可做"渐变背景"而非纯色背景
- 同类库:AppIntro(功能最全的引导页库,内置背景色渐变 + 动画)、MaterialIntroView
9、总结
GuideBackgroundColorAnimation 是一个简洁的 Android 引导页背景色渐变库,核心原理是用 ViewPager 的 positionOffset 驱动 ArgbEvaluator 做颜色插值——不到 30 行核心代码,效果丝滑。虽然库本身较老(2014 年),但"positionOffset + ArgbEvaluator"这个模式至今仍是 ViewPager 滑动动画的万能公式,适用于背景色、缩放、透明度、平移等各种属性驱动。
关键要点:
- 定位:ViewPager 滑动时背景色平滑渐变,引导页经典效果
- 万能公式:positionOffset(0~1 滑动进度)+ ArgbEvaluator(颜色插值)= 背景渐变
- 核心代码不到 30 行,建议手搓而非依赖老库
- positionOffset 模式可扩展到缩放/透明度/平移等任何属性
- ViewPager2 迁移零成本(回调名变、参数不变)
对于需要做"引导页酷炫动画"的 Android 开发者而言,这个库(或者说这个思路)是绕不开的基础招式。理解了"positionOffset 就是万能动画进度条",你就能自己组合出任何"随滑动变化"的效果——背景色、图标缩放、标题平移、透明度过渡,原理全一样。30 行代码教会你一个通用模式,这就是小库的大价值。
参考资料:
