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

如何实现BottomNavigationBar选中时图标动画及解决强转报错

报错根因

Material组件库的BottomNavigationView默认背景是MaterialShapeDrawable,和GradientDrawable无继承关系,直接强转必然抛出类型转换异常。另外你当前代码的操作对象是整个导航栏的背景,和「选中项图标动画」的需求不匹配。

实现方案

内置动画快速接入

Material版BottomNavigationView本身自带选中缩放、透明度、位移的默认动效,无需额外编写逻辑,仅需在布局中配置参数即可生效:

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bot_nav_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:itemIconSize="24dp"
    app:labelVisibilityMode="labeled"
    app:itemActiveIndicatorStyle="@style/Widget.MaterialComponents.BottomNavigationView.ActiveIndicator"
    />

如果需要自定义图标切换的动效(比如变色、路径变形),可以给menu项配置AnimatedStateListDrawable作为图标,状态切换时系统会自动播放对应动画。

自定义复杂选中动画

如果需要实现渐变、多帧变换等自定义动效,通过选项选中监听,单独操作对应位置的图标控件即可:

  • 不要强转整个导航栏的背景,定位到选中项内部的图标ImageView
  • 给当前选中项的图标启动动画,同时重置上一个选中项的状态

核心实现代码:

val navView = findViewById<BottomNavigationView>(R.id.bot_nav_view)
var lastSelectedPos = 0

navView.setOnItemSelectedListener { menuItem ->
    // 计算当前选中项位置
    val currentPos = when(menuItem.itemId) {
        R.id.nav_home -> 0
        R.id.nav_dashboard -> 1
        R.id.nav_notifications -> 2
        else -> 0
    }
    // 获取当前选中项的图标控件
    val selectedItem = navView.findViewById<BottomNavigationItemView>(menuItem.itemId)
    val currentIcon = selectedItem.findViewById<ImageView>(com.google.android.material.R.id.navigation_bar_item_icon_view)

    // 重置上一个选中项的图标状态
    val lastItem = navView.findViewById<BottomNavigationItemView>(navView.menu.getItem(lastSelectedPos).itemId)
    val lastIcon = lastItem.findViewById<ImageView>(com.google.android.material.R.id.navigation_bar_item_icon_view)
    lastIcon.animate().scaleX(1f).scaleY(1f).setDuration(300).start()

    // 执行当前选中项的自定义动画,示例为缩放+颜色渐变
    currentIcon.animate()
        .scaleX(1.2f)
        .scaleY(1.2f)
        .setDuration(300)
        .start()
    
    // 图标本身的渐变、变形逻辑直接操作currentIcon.drawable即可,无需修改导航栏整体背景

    lastSelectedPos = currentPos
    true
}

导航栏整体背景渐变动画实现

如果你的需求是修改整个导航栏的渐变背景,不要强转默认背景,主动给导航栏设置GradientDrawable实例即可:

val navView = findViewById<BottomNavigationView>(R.id.bot_nav_view)
// 主动替换默认背景为GradientDrawable
val gradientBg = GradientDrawable(
    GradientDrawable.Orientation.TOP_BOTTOM,
    intArrayOf(Color.parseColor("#FF9800"), Color.parseColor("#FFEB3B"), Color.parseColor("#2196F3"))
)
navView.background = gradientBg

// 后续动画中直接修改gradientBg的颜色数组即可,不会触发类型转换错误

如果需要保留MaterialShapeDrawable自带的圆角、阴影、描边特性,不要替换背景,直接调用其自带的fillColor、strokeColor属性做动画即可,禁止跨类型强转。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 02:09:18