android MD风格组件(BottomNavigationView,配合lottie使用)(三)

1,491 阅读4分钟

android MD风格组件(BottomNavigationView,配合lottie使用[三])

相关文章:

先来看今天完成的效果!

小红点小红点位置以及样式lottie

基本使用

 <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        style="@style/Widget.MaterialComponents.BottomNavigationView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/cccccc"
        android:theme="@style/bottomButtonNavigationStyle"
        app:itemRippleColor="@color/red"
        app:layout_constraintBottom_toBottomOf="parent"
        app:menu="@menu/button_navigation_menu" />

@style/bottomButtonNavigationStyle:

    <style name="bottomButtonNavigationStyle" parent="Theme.MaterialComponents.Light">
        <!--        是选中颜色-->
        <item name="colorPrimary">@color/purple_500</item>

        <!--        未选中颜色 -->
        <item name="android:textColorSecondary">@color/cccccc</item>
    </style>

@menu/button_navigation_menu:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <!--    tips: BottomNavigationView 最多设置5个tab-->
    <item
        android:id="@+id/itemPage1"
        android:icon="@drawable/ic_home_24"
        android:title="page1" />

    <item
        android:id="@+id/itemPage2"
        android:icon="@drawable/ic_phone_android_24"
        android:title="page2" />

    <item
        android:id="@+id/itemPage3"
        android:icon="@drawable/ic_psychology_24"
        android:title="page3" />
</menu>

参数介绍:

参数说明
android:theme常用来设置选中按钮颜色
app:itemRippleColor水波纹颜色 [app:itemRippleColor="@null" 去除水波纹!]
app:itemIconTinticon色调
app:menu设置tab
app:itemIconSize按钮大小
app:labelVisibilityMode按钮模式

app:labelVisibilityMode模式4种模式对比:

模式说明效果图
autoitem 少于等于 3 个时,标题处于显示状态;大于等于 4 个,选中才显示标题
selected选中才显示标题
labeled一直显示
unlabeled只显示icon

style参数:

style参数说明
Widget.MaterialComponents.BottomNavigationView默认
Widget.MaterialComponents.BottomNavigationView.Colored彩色(看着很丑..)
Widget.MaterialComponents.BottomNavigationView.PrimarySurface支持深色主题

官方文档

tips: BottomNavigationView 最多设置5个tab,否则会提示

"Maximum number of items supported by "
              + viewClassName
              + " is "
              + maxItemCount
              + ". Limit can be checked with "
              + viewClassName
              + "#getMaxItemCount()

源码分析,两张图直接搞明白: 图一: 在这里插入图片描述 图二: 在这里插入图片描述

设置小红点及其位置

设置小红点需要通过BottomNavigationView#BadgeDrawable来设置

private val badgeGravityValues = intArrayOf(
        BadgeDrawable.TOP_END, // 右上
        BadgeDrawable.TOP_START, // 左上
        BadgeDrawable.BOTTOM_END, // 右下
        BadgeDrawable.BOTTOM_START // 左下
    )

// 设置小红点
 binding.bottomNavigationView.apply {
     val itemId = menu.getItem(index).itemId

     getOrCreateBadge(itemId).apply {
         isVisible = true
         number += 1
         
        // 设置位置
         badgeGravity = badgeGravityValues[indexOfChild]
     }
 }

辅助图: 在这里插入图片描述 来看看效果:

小坑:

长按事件的时候,回弹出提示框,例如这样


你可以通过拦截长按事件来捕获它

binding.bottomNavigationView.menu.forEach {
        binding.bottomNavigationView.findViewById<View>(it.itemId)
             .setOnLongClickListener { true }
     }

BottomNavigationView 配合lottie实现联动效果

Lottie官方使用文档

implementation com.airbnb.android:lottie:3.6.0"

lottie 类型:

  • LottieAnimationView 扩展 ImageView 并且是加载 Lottie 动画的默认和最简单的方法。
  • LottieDrawableLottieAnimationView 有大部分相同的 API,但你可以在任何你想要的视图上使用它。
  • LottieComposition是动画的无状态模型表示。只要您需要,此文件就可以安全地缓存,并且可以在绘图/视图之间自由重用。
  • LottieCompositionFactory 允许您从多个输入创建 LottieComposition。这就是setAnimation(...)API 在后台使用LottieDrawable和LottieAnimationView使用的内容。工厂方法也与这些类共享相同的缓存。

这里结合主要用到了LottieDrawable

来看完整代码思路:


class NavigationBottomViewModel : ViewModel() {
    // 注意 最多能放5个!!(源码规定)
    private val pairAnimationList = listOf(
        "tissue.json" to "首页",
        "chemical.json" to "通讯录",
        "cow.json" to "朋友圈",
        "astronaout.json" to "我的",
    )

    private var mCurrentPosition = 0

    fun initBottomNavigationView(bottomNav: BottomNavigationView) {
        bottomNav.menu.apply {
            for (i in pairAnimationList.indices) {
                // 添加title
                add(Menu.NONE, i, Menu.NONE, pairAnimationList[i].second)

                // 设置lottie
                setLottieDrawable(pairAnimationList, bottomNav, i)
            }
        }
        // 初始化点击监听
        initClickEvent(bottomNav)
    }

    private fun initClickEvent(bottomNav: BottomNavigationView) {
        // 监听选中事件
        bottomNav.setOnItemSelectedListener(getOnNavigationItemSelectedListener(bottomNav))
        bottomNav.setOnItemReselectedListener {
            getOnNavigationItemReselectedListener(
                bottomNav
            )
        }

        // 默认选中第一个
        bottomNav.selectedItemId = 0

        // 禁止长按弹出 拦截长按事件
        bottomNav.menu.forEach {
            val menuItemView = bottomNav.findViewById<BottomNavigationItemView>(it.itemId)
            menuItemView.setOnLongClickListener {
                true
            }
        }
    }

    // 监听变化
    // Listener for handling selection events on bottom navigation items.
    // 事件监听器来处理选择底部导航项。
    private fun getOnNavigationItemSelectedListener(lottieBottomNavView: BottomNavigationView) =
        NavigationBarView.OnItemSelectedListener { item ->
            handleNavigationItem(item, lottieBottomNavView)
            true
        }

    // Listener for handling reselection events on bottom navigation items
    // 用于处理底部导航项上的重新选择事件的侦听器
    private fun getOnNavigationItemReselectedListener(lottieBottomNavView: BottomNavigationView) =
        NavigationBarView.OnItemReselectedListener { item ->
            handleNavigationItem(item, lottieBottomNavView)
        }

    /*
   * 作者:android 超级兵
   * 创建时间: 1/24/22 7:46 PM
   * TODO 将lottie转变为drawable 设置给menu
   */
    private fun Menu.setLottieDrawable(
        lottieAnimationList: List<Pair<String, String>>,
        bottomNav: BottomNavigationView,
        position: Int
    ) {
        // 转变为lottieDrawable
        findItem(position).icon =
            replaceLottieDrawable(lottieAnimationList[position].first, bottomNav)
    }


    /*
     * 作者:android 超级兵
     * 创建时间: 1/26/22 1:50 PM
     * TODO 选中监听
     */
    private fun handleNavigationItem(item: MenuItem, bottomNav: BottomNavigationView) {
        handlePlayLottieAnimation(item, bottomNav)
        mCurrentPosition = item.itemId
    }

    private fun handlePlayLottieAnimation(item: MenuItem, bottomNav: BottomNavigationView) {
        val currentIcon = item.icon as? LottieDrawable
        currentIcon?.apply {
            // 开启动画
            playAnimation()

            // 无限播放
//            loop(true)
        }

        // 处理 tab 切换,icon 对应调整
        if (item.itemId != mCurrentPosition) {
            bottomNav.menu.findItem(mCurrentPosition).icon =
                replaceLottieDrawable(
                    pairAnimationList[mCurrentPosition].first,
                    bottomNav
                )
        }
    }

    /**
     * 替换成 LottieDrawable
     */
    private fun replaceLottieDrawable(
        jsonKey: String,
        bottomNavigationView: BottomNavigationView
    ): LottieDrawable {
        return LottieDrawable().apply {
            val result = LottieCompositionFactory.fromAssetSync(
                // 加载lottie 数据
                bottomNavigationView.context.applicationContext, jsonKey
            )
            callback = bottomNavigationView

            // 设置动画
            composition = result.value
        }
    }
}

使用:

private val viewModel: NavigationBottomViewModel by viewModels()

// 初始化lottie 与 bottomNavView 结合起来
viewModel.initBottomNavigationView(binding.lottieBottomNavView)

lottie图片出处,购买其他lottie图片要掏美子,有点贵,所以就选了几张免费的图来用用..

思路参考自

官方的效果

先来看看官方实现的效果:


这种效果我是看material design源码看到的,因为涉及到很多的代码,这里自分析完成思路,具体细节请下载完整代码查看

先来看一眼布局: 在这里插入图片描述 具体细节: 在这里插入图片描述

思路分析: 官方感觉像是自定义svg图,来实现这个效果的,说实话,要给我我是弄不出来.. 但是感觉这种代码像是自动生成的.😂

下集预告(CoordinatorLayout与自定义anchor):


完整代码

相关文章:

今年的文章就写到这里,感谢你的关注点赞 ,谢谢!

原创不易,您的点赞就是对我最大的支持!