已实现Toolbar背景色随AppBarLayout折叠变化,如何修改菜单项颜色?
嘿,我知道你已经搞定了AppBarLayout折叠时修改Toolbar背景色的功能,现在想让Toolbar上的菜单项颜色也跟着折叠状态同步变化对吧?这个需求很常见,咱们可以通过监听AppBarLayout的滚动偏移量,动态给菜单项图标着色来实现,下面给你两种实用的方案:
方案一:直接监听AppBarLayout偏移量(快速实现)
这个方法简单直接,适合单个页面使用。核心思路是计算AppBarLayout的折叠比例,根据比例切换或渐变菜单项颜色。
首先在你的Activity/Fragment里获取AppBarLayout和Toolbar实例,然后添加偏移监听:
// 假设你已经通过ViewBinding或findViewById拿到了实例 val appBarLayout = binding.appBarLayout val toolbar = binding.toolbar // 添加偏移变化监听 appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset -> // 计算折叠进度:verticalOffset的范围是0到 -appBarLayout.totalScrollRange val scrollRange = appBarLayout.totalScrollRange val collapseRatio = Math.abs(verticalOffset).toFloat() / scrollRange.toFloat() // 方式1:阈值切换(比如折叠超过50%时切换颜色) if (collapseRatio > 0.5f) { // 折叠到一半以上,设置菜单项为深色 setToolbarMenuColor(toolbar, R.color.dark_primary) } else { // 展开状态,设置菜单项为浅色 setToolbarMenuColor(toolbar, R.color.light_primary) } // 方式2:渐变过渡(更丝滑的效果) val evaluator = ArgbEvaluator() val currentColor = evaluator.evaluate( collapseRatio, ContextCompat.getColor(this, R.color.light_primary), ContextCompat.getColor(this, R.color.dark_primary) ) as Int setToolbarMenuColor(toolbar, currentColor) }) // 封装的设置菜单项颜色的工具方法 private fun setToolbarMenuColor(toolbar: Toolbar, colorRes: Int) { val color = ContextCompat.getColor(this, colorRes) // 设置导航图标颜色 toolbar.navigationIcon?.setTint(color) // 遍历所有菜单项设置颜色 toolbar.menu.forEach { menuItem -> menuItem.icon?.setTint(color) } }
注意事项:
- 如果你的Toolbar菜单是动态加载的(比如在
onCreateOptionsMenu里添加),记得在菜单加载完成后同步调用setToolbarMenuColor,避免初始颜色不一致。 - 页面销毁时记得移除监听,防止内存泄漏:
override fun onDestroy() { super.onDestroy() appBarLayout.removeOnOffsetChangedListener(this) }
方案二:自定义Behavior(复用性更高)
如果你的App多个页面都需要这个效果,建议用CoordinatorLayout的Behavior来实现,代码更解耦,复用性强。
首先自定义一个Behavior类:
class ToolbarMenuColorBehavior : AppBarLayout.ScrollingViewBehavior() { private var toolbar: Toolbar? = null private var lightColor: Int = 0 private var darkColor: Int = 0 private val offsetListener = AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> val scrollRange = appBarLayout.totalScrollRange val collapseRatio = Math.abs(verticalOffset).toFloat() / scrollRange.toFloat() // 用ArgbEvaluator实现颜色渐变 val evaluator = ArgbEvaluator() val currentColor = evaluator.evaluate(collapseRatio, lightColor, darkColor) as Int toolbar?.run { navigationIcon?.setTint(currentColor) menu.forEach { it.icon?.setTint(currentColor) } } } override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean { if (dependency is AppBarLayout) { toolbar = parent.findViewById(R.id.toolbar) lightColor = ContextCompat.getColor(parent.context, R.color.light_primary) darkColor = ContextCompat.getColor(parent.context, R.color.dark_primary) dependency.addOnOffsetChangedListener(offsetListener) return true } return super.layoutDependsOn(parent, child, dependency) } override fun onDetachedFromLayoutParams() { super.onDetachedFromLayoutParams() // 移除监听,防止内存泄漏 (dependency as? AppBarLayout)?.removeOnOffsetChangedListener(offsetListener) } }
然后在布局文件中,给和AppBarLayout联动的滚动视图(比如NestedScrollView)设置这个Behavior:
<androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior=".ToolbarMenuColorBehavior"> <!-- 你的页面内容 --> </androidx.core.widget.NestedScrollView>
额外提示:
- 确保你的菜单项图标是矢量图(VectorDrawable),如果用普通PNG图,着色效果可能不理想。如果必须用PNG,可以在Drawable的xml中设置
android:tintMode="src_in"来优化着色效果。 - 如果需要调整颜色切换的阈值,只需要修改
collapseRatio的判断条件(比如改成0.3f就是折叠30%时切换)。
内容的提问来源于stack exchange,提问作者AminA2
相关产品推荐
相关产品推荐

