其他分享
首页 > 其他分享> > BottomNavigationView简单使用,增加小红点,增加中间操作按钮

BottomNavigationView简单使用,增加小红点,增加中间操作按钮

作者:互联网

大体效果

可以这样用:

首先布局文件中添加BottomNavigationView和ViewPager2

新建list,保存需要展示的fragment

fragmentList.add(DFragment())
fragmentList.add(EFragment())
fragmentList.add(FFragment())
fragmentList.add(GFragment())

新建list,保存底部按钮信息

TabItem第三个参数设置为true代表当前按钮是一个操作按钮

 tabItems.add(TabItem("首页", R.mipmap.ic_ycq_home))
tabItems.add(TabItem("任务", R.mipmap.ic_ycq_task))
//        tabItems.add(TabItem("", R.mipmap.ic_launcher_round, true))
tabItems.add(TabItem("测试", R.mipmap.ic_ycq_buy))
tabItems.add(TabItem("我的1", R.mipmap.ic_ycq_mine))

然后直接调用就可以了

val util = BottomNavigationViewUtil.getInstance()
            .init(
                this,
                mBinding.navigationView,
                mBinding.vp2,
                fragmentList,
                tabItems,
                Color.parseColor("#ff0000"),
                Color.parseColor("#999999")
            ).addOnlyOperateClick {
                println("只有操作的按钮点击了,在父Fragment中触发了方法")
                ToastDialog(requireContext(), "只有操作的按钮点击了,在父Fragment中触发了方法").show()
            }

        mBinding.navigationView.postDelayed({
            util.addTabItemRedCirclePoint(3, 58)
            util.addTabItemRedCirclePoint(0, 21)

        }, 5 * 1000)

具体BottomNavigationViewUtil

import android.content.res.ColorStateList
import android.view.View
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.appcompat.widget.AppCompatImageView
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.bottomnavigation.BottomNavigationItemView
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.navigation.NavigationBarView
import com.ycq.ycqlibrary.R

/**
 * 一个可以将BottomNavigationView和ViewPager2直接绑定的工具类
 * 可以添加小红点,修改数字
 * 可以添加操作项
 */
class BottomNavigationViewUtil private constructor() {
    companion object {
        @Volatile
        private var instance: BottomNavigationViewUtil? = null

        fun getInstance(): BottomNavigationViewUtil {
            return instance ?: synchronized(this) {
                instance ?: BottomNavigationViewUtil()
            }
        }
    }

    /**
     * 用于保存索引位置的小红点
     */
    private val map = mutableMapOf<Int, TextView>()

    /**
     * 上下文
     */
    private lateinit var fragment: Fragment

    /**
     *
     */
    private var bottomNavigationView: BottomNavigationView? = null

    /**
     *
     */
    private var viewPager2: ViewPager2? = null

    /**
     * 展示的fragment的列表
     */
    private var fragments = mutableListOf<Fragment>()

    /**
     * 底部按钮列表,可以包含只有操作的按钮
     */
    private var tabItems = mutableListOf<TabItem>()

    /**
     * 选中时按钮显示的颜色值
     */
    private var selectedColor: Int = -1

    /**
     * 没有选中时按钮显示的颜色值
     */
    private var unselectedColor: Int = -1

    /**
     * 底部按钮的菜单按钮,通过该View可以添加小红点,添加操作按钮
     */
    private var menuView: BottomNavigationMenuView? = null

    /**
     * 当前选中的索引
     */
    private var currentSelectedIndex = 0

    /**
     * 操作按钮索引
     */
    private var onlyOperateIndex = -1

    /**
     * 操作按钮图标
     */
    private var onlyOperateIcon = -1

    /**
     * 初始化
     * @param fragment Fragment
     * @param bottomNavigationView BottomNavigationView
     * @param viewPager2 ViewPager2
     * @param fragments MutableList<Fragment>
     * @param tabItems MutableList<TabItem>
     * @param selectedColor Int
     * @param unselectedColor Int
     * @return BottomNavigationViewUtil
     */
    fun init(
        fragment: Fragment,
        bottomNavigationView: BottomNavigationView,
        viewPager2: ViewPager2,
        fragments: MutableList<Fragment>,
        tabItems: MutableList<TabItem>,
        @ColorInt selectedColor: Int,
        @ColorInt unselectedColor: Int
    ): BottomNavigationViewUtil {
        this.fragment = fragment
        addBottomNavigationView(bottomNavigationView)
        addViewPager2(viewPager2)
        addFragments(fragments)
        addItems(tabItems)
        setSelectedColor(selectedColor)
        setUnselectedColor(unselectedColor)
        attach()
        return this
    }

    /**
     * 添加底部组件
     * @param bottomNavigationView BottomNavigationView
     * @return BottomNavigationViewUntil
     */
    private fun addBottomNavigationView(bottomNavigationView: BottomNavigationView): BottomNavigationViewUtil {
        this.bottomNavigationView = bottomNavigationView
        menuView = bottomNavigationView.getChildAt(0) as BottomNavigationMenuView
        return this
    }

    /**
     * 添加ViewPager2
     * @param viewPager2 ViewPager2
     * @return BottomNavigationViewUntil
     */
    private fun addViewPager2(viewPager2: ViewPager2): BottomNavigationViewUtil {
        this.viewPager2 = viewPager2
        return this
    }

    /**
     * 添加Fragment
     * @param fragments MutableList<Fragment>
     * @return BottomNavigationViewUntil
     */
    private fun addFragments(fragments: MutableList<Fragment>): BottomNavigationViewUtil {
        this.fragments.apply {
            clear()
            addAll(fragments)
        }
        return this
    }

    /**
     * 添加底部按钮信息
     * @param tabItems MutableList<TabItem>
     * @return BottomNavigationViewUntil
     */
    private fun addItems(tabItems: MutableList<TabItem>): BottomNavigationViewUtil {
        this.tabItems.apply {
            clear()
            addAll(tabItems)
        }
        return this
    }

    /**
     * 设置选中颜色
     * @param selectedColor Int
     * @return BottomNavigationViewUntil
     */
    private fun setSelectedColor(@ColorInt selectedColor: Int): BottomNavigationViewUtil {
        this.selectedColor = selectedColor
        return this
    }

    /**
     * 设置未选中时颜色
     * @param unselectedColor Int
     * @return BottomNavigationViewUntil
     */
    private fun setUnselectedColor(@ColorInt unselectedColor: Int): BottomNavigationViewUtil {
        this.unselectedColor = unselectedColor
        return this
    }


    /**
     * 绑定BottomNavigationView和ViewPager2
     */
    private fun attach(): BottomNavigationViewUtil {
        if (fragments.size == 0 || tabItems.size == 0) {
            error("请在调用该方法前先调用addBottomNavigationView()和addItems()")
        }
        initTabItem()
        initBottomNavigationViewAndViewPager2()
        return this
    }


    /**
     * 初始化底部按钮
     */
    private fun initTabItem() {
        bottomNavigationView?.menu.apply {
            tabItems.forEachIndexed { index, tabItem ->
                this?.add(0, index, index, tabItem.title)
                this?.getItem(index)!!.setIcon(tabItem.icon)
                if (tabItem.onlyOperate) {
                    onlyOperateIndex = index
                    onlyOperateIcon = tabItem.icon
                }
            }
        }
        bottomNavigationView?.apply {
            labelVisibilityMode = NavigationBarView.LABEL_VISIBILITY_LABELED
            val colorStateList = getColorStateList()
            itemIconTintList = colorStateList
            itemTextColor = colorStateList
        }

        if (onlyOperateIndex != -1) {
            val itemView = menuView!!.getChildAt(onlyOperateIndex) as BottomNavigationItemView
            val badge =
                fragment.layoutInflater.inflate(R.layout.menu_other, menuView, false)
            val ivIcon = badge.findViewById<AppCompatImageView>(R.id.ivIcon)
            ivIcon.setImageResource(onlyOperateIcon)
            badge.setOnClickListener {
                operate()
            }
            itemView.addView(badge)
        }
    }

    /**
     * 初始化view并绑定事件
     */
    private fun initBottomNavigationViewAndViewPager2() {
        var onlyOperate = false
        viewPager2?.apply {
            isUserInputEnabled = false
            adapter = BottomTabAdapter(fragment, fragments)
            //注释:出现了BottomNavigationView回调调用两次的问题时,BottomNavigationView选中时设置了VIewpager2选中对应Item。
            // 而ViewPager2设置了item选中监听,在这个监听中又设置了BottomNavigationView选中对应Item
            //所以要想viewpager2滚动,如要在BottomNavigationView监听中处理一下
//            registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
//                override fun onPageSelected(position: Int) {
//                    super.onPageSelected(position)
//                    bottomNavigationView?.selectedItemId =
//                        bottomNavigationView!!.menu.getItem(position).itemId
//                }
//            })
        }
        bottomNavigationView?.apply {
            setOnNavigationItemSelectedListener { menuItem ->
                val order = menuItem.order
                when {
                    order == onlyOperateIndex -> {
                        println("点击只有操作的按钮了")
                        onlyOperate = true
                    }
                    order < onlyOperateIndex -> {
                        onlyOperate = false
                        println("点击左边的按钮了")
                        viewPager2?.setCurrentItem(order, false)
                        currentSelectedIndex = order
                    }
                    else -> {
                        onlyOperate = false
                        println("点击右边的按钮了啊")
                        viewPager2?.setCurrentItem(order - 1, false)
                        currentSelectedIndex = order

                    }
                }
                true
            }
            setOnNavigationItemReselectedListener { menuItem ->
                println("Reselected:" + menuItem.title)
            }
        }


    }

    /**
     * 生成底部颜色
     * @return ColorStateList
     */
    private fun getColorStateList(): ColorStateList {
        val states = arrayOfNulls<IntArray>(2)
        states[0] = IntArray(1) { android.R.attr.state_checked }
        states[1] = IntArray(1) { 0 }
        val colors = intArrayOf(selectedColor, unselectedColor)
        return ColorStateList(states, colors)
    }


    /**
     * 添加对应索引位置小红点
     * @param index Int
     * @param num Int
     * @return BottomNavigationViewUntil
     */
    fun addTabItemRedCirclePoint(index: Int, num: Int): BottomNavigationViewUtil {
        if (menuView == null) {
            error("请在调用该方法前先调用attach()")
        }
        if (index >= tabItems.size) {
            error("请填入正确索引值")
        }
        val itemView = menuView!!.getChildAt(index) as BottomNavigationItemView
        val badge = fragment.layoutInflater.inflate(R.layout.menu_badge, menuView, false)
        val tvNum = badge.findViewById<TextView>(R.id.tvNum)
        tvNum.text = num.toString()
        map[index] = tvNum
        itemView.addView(badge, 0)
        return this
    }


    /**
     * 改变红点展示的值,当值小于等于0时,红点隐藏
     * @param index Int
     * @param num Int
     */
    fun changeRedCirclePointNum(index: Int, num: Int) {
        if (index >= tabItems.size) {
            error("请填入正确索引值")
        }
        val tvNum = map[index]
        if (num <= 0) {
            tvNum?.visibility = View.INVISIBLE
        } else {
            tvNum?.text = num.toString()
        }
    }


    var operate: () -> Unit = {}
    fun addOnlyOperateClick(operate: () -> Unit = {}): BottomNavigationViewUtil {
        this.operate = operate
        return this
    }

}

class TabItem(
    val title: String = "",
    @DrawableRes val icon: Int,
    val onlyOperate: Boolean = false
)

class BottomTabAdapter(
    activity: FragmentActivity,
    private val fragmentList: MutableList<Fragment>
) : FragmentStateAdapter(activity) {
    constructor(
        fragment: Fragment,
        fragmentList: MutableList<Fragment>
    ) : this(fragment.requireActivity(), fragmentList)

    override fun getItemCount() = fragmentList.size

    override fun createFragment(position: Int): Fragment {
        return fragmentList[position]
    }
}

两个布局文件,可以自己修改

menu_badge
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.ycq.ycqlibrary.view.SquareTextView
        android:id="@+id/tvNum"
        android:layout_width="12dp"
        android:layout_height="12dp"
        android:textColor="@color/white"
        android:text="12"
        android:gravity="center"
        android:textSize="7dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginLeft="12dp"
        android:layout_marginTop="2dp"
        android:background="@drawable/shape_tab_red_circle" />
</FrameLayout>
menu_other
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.appcompat.widget.AppCompatImageView
        android:id="@+id/ivIcon"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="5dp"
        android:scaleType="fitXY" />
</FrameLayout>

标签:return,Int,小红点,private,tabItems,按钮,fun,BottomNavigationViewUtil,BottomNavigation
来源: https://blog.csdn.net/ycq2758419714/article/details/120327312