如何实现类似Google Trips行程页的Toolbar:滚动切换菜单图标颜色
实现CollapsingToolbar滚动时切换菜单图标颜色(仿Google Trips)
我刚帮不少开发者搞定过类似的需求,结合Google Trips的Toolbar样式,给你一套能直接复用的方案:
核心思路
CollapsingToolbarLayout滚动时,AppBarLayout会产生偏移量变化。我们可以通过监听这个偏移量,判断Toolbar的折叠状态(完全展开/部分折叠/完全折叠),然后动态切换菜单图标的颜色——展开时白色,折叠后灰色,甚至可以做渐变过渡效果。
具体实现步骤
1. 配置布局文件
首先确保你的布局里包含AppBarLayout、CollapsingToolbarLayout和Toolbar,结构大概是这样:
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:id="@+id/app_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:fitsSystemWindows="true" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <com.google.android.material.appbar.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="250dp" android:fitsSystemWindows="true" app:contentScrim="@color/white" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <!-- 这里放CollapsingToolbar里的头部内容,比如背景图、标题等 --> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/trip_header" app:layout_collapseMode="parallax"/> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> </com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.AppBarLayout> <!-- 可滚动的内容区域,比如RecyclerView/NestedScrollView --> <androidx.core.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <!-- 内容布局 --> </androidx.core.widget.NestedScrollView> </androidx.coordinatorlayout.widget.CoordinatorLayout>
注意:CollapsingToolbarLayout的contentScrim设为白色(折叠后的背景),Toolbar的popupTheme用浅色主题,避免菜单弹窗样式冲突。
2. 监听滚动偏移,切换图标颜色
在你的Activity或Fragment里,给AppBarLayout设置偏移监听,根据折叠程度调整图标颜色:
Kotlin代码示例:
class TripActivity : AppCompatActivity() { private lateinit var appBarLayout: AppBarLayout private lateinit var toolbar: Toolbar private val whiteColor by lazy { ContextCompat.getColor(this, R.color.white) } private val grayColor by lazy { ContextCompat.getColor(this, R.color.gray_600) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_trip) appBarLayout = findViewById(R.id.app_bar) toolbar = findViewById(R.id.toolbar) setSupportActionBar(toolbar) // 初始化菜单图标为白色 updateMenuIconColor(whiteColor) // 监听AppBar滚动偏移 appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBar, verticalOffset -> // 计算折叠比例:verticalOffset是负数,绝对值越大折叠程度越高 val collapseRatio = Math.abs(verticalOffset).toFloat() / appBar.totalScrollRange.toFloat() // 完全折叠时(比例接近1)切换为灰色,否则白色;也可以做渐变过渡 if (collapseRatio >= 0.9f) { // 接近完全折叠时切换 updateMenuIconColor(grayColor) } else { updateMenuIconColor(whiteColor) } // 如果需要渐变过渡效果,可以用这个: // val blendedColor = blendColors(whiteColor, grayColor, collapseRatio) // updateMenuIconColor(blendedColor) }) } // 更新所有菜单图标的颜色 private fun updateMenuIconColor(color: Int) { toolbar.menu?.let { menu -> for (i in 0 until menu.size()) { val menuItem = menu.getItem(i) menuItem.icon?.let { icon -> DrawableCompat.setTint(icon, color) } } } } // 可选:颜色渐变混合方法 private fun blendColors(color1: Int, color2: Int, ratio: Float): Int { val inverseRatio = 1f - ratio val r = (Color.red(color1) * inverseRatio + Color.red(color2) * ratio).toInt() val g = (Color.green(color1) * inverseRatio + Color.green(color2) * ratio).toInt() val b = (Color.blue(color1) * inverseRatio + Color.blue(color2) * ratio).toInt() return Color.rgb(r, g, b) } override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.trip_toolbar_menu, menu) return true } }
Java代码示例:
public class TripActivity extends AppCompatActivity { private AppBarLayout appBarLayout; private Toolbar toolbar; private int whiteColor; private int grayColor; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_trip); appBarLayout = findViewById(R.id.app_bar); toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); whiteColor = ContextCompat.getColor(this, R.color.white); grayColor = ContextCompat.getColor(this, R.color.gray_600); // 初始化图标为白色 updateMenuIconColor(whiteColor); appBarLayout.addOnOffsetChangedListener((appBar, verticalOffset) -> { float collapseRatio = Math.abs(verticalOffset) / (float) appBar.getTotalScrollRange(); if (collapseRatio >= 0.9f) { updateMenuIconColor(grayColor); } else { updateMenuIconColor(whiteColor); } }); } private void updateMenuIconColor(int color) { Menu menu = toolbar.getMenu(); if (menu != null) { for (int i = 0; i < menu.size(); i++) { MenuItem menuItem = menu.getItem(i); Drawable icon = menuItem.getIcon(); if (icon != null) { DrawableCompat.setTint(icon, color); } } } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.trip_toolbar_menu, menu); return true; } }
3. 补充说明
- 菜单图标建议用矢量图(VectorDrawable),这样tint效果更稳定,避免出现颜色失真。
- 如果你想实现更平滑的渐变过渡,就用上面代码里的
blendColors方法,根据折叠比例动态混合白色和灰色,视觉效果更接近Google Trips的原生体验。 - 调整
collapseRatio >= 0.9f的阈值,可以控制图标切换的时机,比如在折叠到90%的时候切换颜色,你可以根据自己的Toolbar高度调整这个值。
内容的提问来源于stack exchange,提问作者pop
相关产品推荐
相关产品推荐

