如何实现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
相关产品推荐
相关产品推荐

