GuideBackgroundColorAnimation 详解:ViewPager 滑动时背景色渐变

QuibblerQuibbler 2020-02-03 约 16 分钟 620 次阅读

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 行代码教会你一个通用模式,这就是小库的大价值。

参考资料:

        RonanCN/GuideBackgroundColorAnimation(GitHub 仓库)

        ArgbEvaluator(Android 官方 API 文档)

相关推荐

精选
Airbnb开源项目
开源

Airbnb开源项目

Airbnb Engineering & Data ScienceAirflow Use Apache Airflow (incubating) to author workflows as directed acyclic graphs (DAGs) of tasks12,263Airpal Web UI for PrestoDB2,502Aerosolve A machine learning

1.8k
OkHttp线程池和连接池
开源

OkHttp线程池和连接池

OkHttp线程池和连接池了解了OkHttp的网络请求流程以及拦截器实现原理,再关注OkHttp中两个重要的:OkHttp的线程池和连接池。1、OkHttp线程池在OkHttp网络请求流程一文中,我们分析了OkHttp异步和同步请求流程。请求最后都在Dispatcher中分发调度处理,最后被ExecutorService执行。1.1、DispatcherDispatcher中执行任务的执行器是ex

5.2k
优美的开源动效库:Lottie
开源

优美的开源动效库:Lottie

优美的开源动效库:Lottie1、强大的动效LottieLottie是一个适用于Android,iOS,Web和Windows的库,它可以使用Bodymovin解析以json格式导出的Adobe After Effects动画,并在移动设备和Web上原生渲染它们!GitHub:https://github.com/airbnb/lottie-androidLottie官网:http://airbn

4.3k