You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android开发:如何随ViewPager滑动为BottomNavigationView图标实现部分着色?

嘿,这个需求我太熟了!Chrome那种滑动时底部导航图标渐变着色的效果,实现起来其实挺直观的,咱们一步步来搞定:

核心思路

通过监听ViewPager的滑动进度,计算页面切换的偏移量,然后利用颜色渐变算法,动态修改BottomNavigationView中对应图标的着色效果,实现从选中色到未选中色的平滑过渡。

具体实现步骤

1. 准备支持着色的图标资源

注意:图标必须是支持着色的资源,比如VectorDrawable或者纯白色的PNG(带透明通道),否则后续的颜色过滤不会生效。你可以在res/drawable下放置矢量图标,或者确保PNG图标本身是无底色的。

2. 基础交互关联

先把ViewPager和BottomNavigationView的基础联动做好:

  • 点击BottomNavigationView的菜单项时,ViewPager切换到对应页面
  • ViewPager切换页面时,BottomNavigationView选中对应菜单项

代码示例(Kotlin + ViewPager2)

// 关联底部导航点击事件
bottomNavigationView.setOnItemSelectedListener { menuItem ->
    val targetPosition = bottomNavigationView.menu.indexOf(menuItem)
    viewPager.currentItem = targetPosition
    true
}

// 关联ViewPager页面选中事件
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
    override fun onPageSelected(position: Int) {
        super.onPageSelected(position)
        bottomNavigationView.selectedItemId = bottomNavigationView.menu.getItem(position).itemId
        // 页面选中时重置所有图标颜色,避免过渡残留
        resetBottomNavIcons()
    }
})

3. 实现滑动时的图标渐变着色

核心是监听ViewPager的滑动偏移量,用ArgbEvaluator计算过渡颜色,给当前和下一个菜单项的图标设置动态颜色过滤。

新增颜色过渡处理函数

private fun updateBottomNavIcons(currentPosition: Int, offset: Float) {
    val selectedColor = ContextCompat.getColor(this, R.color.bottom_nav_selected)
    val unselectedColor = ContextCompat.getColor(this, R.color.bottom_nav_unselected)
    val colorEvaluator = ArgbEvaluator()

    // 处理当前页面的图标:从选中色过渡到未选中色
    val currentMenuItem = bottomNavigationView.menu.getItem(currentPosition)
    val currentTransitionColor = colorEvaluator.evaluate(offset, selectedColor, unselectedColor) as Int
    // 必须mutate(),避免共享Drawable实例导致所有图标颜色同步变化
    val currentIcon = currentMenuItem.icon.mutate()
    currentIcon.colorFilter = PorterDuffColorFilter(currentTransitionColor, PorterDuff.Mode.SRC_IN)
    currentMenuItem.icon = currentIcon

    // 处理下一个页面的图标:从未选中色过渡到选中色(如果存在下一页)
    if (currentPosition < bottomNavigationView.menu.size() - 1) {
        val nextMenuItem = bottomNavigationView.menu.getItem(currentPosition + 1)
        val nextTransitionColor = colorEvaluator.evaluate(offset, unselectedColor, selectedColor) as Int
        val nextIcon = nextMenuItem.icon.mutate()
        nextIcon.colorFilter = PorterDuffColorFilter(nextTransitionColor, PorterDuff.Mode.SRC_IN)
        nextMenuItem.icon = nextIcon
    }
}

// 重置所有图标到正确的选中/未选中状态
private fun resetBottomNavIcons() {
    val selectedColor = ContextCompat.getColor(this, R.color.bottom_nav_selected)
    val unselectedColor = ContextCompat.getColor(this, R.color.bottom_nav_unselected)
    
    for (i in 0 until bottomNavigationView.menu.size()) {
        val menuItem = bottomNavigationView.menu.getItem(i)
        val targetColor = if (i == bottomNavigationView.selectedItemPosition) selectedColor else unselectedColor
        val icon = menuItem.icon.mutate()
        icon.colorFilter = PorterDuffColorFilter(targetColor, PorterDuff.Mode.SRC_IN)
        menuItem.icon = icon
    }
}

绑定滑动监听

在之前的OnPageChangeCallback中添加滑动监听:

override fun onPageScrolled(
    position: Int,
    positionOffset: Float,
    positionOffsetPixels: Int
) {
    super.onPageScrolled(position, positionOffset, positionOffsetPixels)
    // 实时更新图标颜色
    updateBottomNavIcons(position, positionOffset)
}

4. 适配旧版ViewPager(可选)

如果你用的是旧版ViewPager而非ViewPager2,只需把监听换成OnPageChangeListener即可:

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        updateBottomNavIcons(position, positionOffset);
    }

    @Override
    public void onPageSelected(int position) {
        bottomNavigationView.setSelectedItemId(bottomNavigationView.getMenu().getItem(position).getItemId());
        resetBottomNavIcons();
    }

    @Override
    public void onPageScrollStateChanged(int state) {}
});
额外提示
  • 如果你还想给底部导航的文字也加上渐变效果,逻辑和图标完全一致,只需修改TextView的setTextColor即可
  • 可以根据需求调整过渡的缓动效果,比如给offset加上动画插值器,让渐变更自然

内容的提问来源于stack exchange,提问作者Soheil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 13:57:37