Android-BottomNavigationView(支持角标,加载网络图标..)+vp+fg

基本使用应该基本都会,我是基于最新的工程环境来搞的,这两天过程中遇到一些问题。比如按照网上一些资料,

1 . 去掉水波纹

实际我发现没有效果。然后我跟踪了一下源码设置水波纹的地方:

   int itemBackground = a.getResourceId(R.styleable.BottomNavigationView_itemBackground, 0);
    if (itemBackground != 0) {
      menuView.setItemBackgroundRes(itemBackground);
    } else {
      ColorStateList itemRippleColor =
          MaterialResources.getColorStateList(
              context, a, R.styleable.BottomNavigationView_itemRippleColor);
      setItemRippleColor(itemRippleColor);
    }

我发现当你不设置这个的时候或者设置为null的时候,其实还会去找R.styleable.BottomNavigationView_itemRippleColor。 怎么感觉跟其他人说的不一样,难道是我理解错了?

于是我重新了Style里面的 itemRippleColor为null - 其他属性也一并贴出

   <!--    BottomNavigationView属性-->
    <style name="BottomNavigationViewTheme" parent="Widget.MaterialComponents.BottomNavigationView">
        <!--波纹颜色无-->
        <item name="itemRippleColor">@null</item>
        <item name="itemTextAppearanceActive">@style/BottomNavigationViewTheme.TextAppearance_Selected
        </item>
        <item name="itemTextAppearanceInactive">@style/BottomNavigationViewTheme.TextAppearance
        </item>
    </style>
    <!--    BottomNavigationView 字体属性-->
    <style name="BottomNavigationViewTheme.TextAppearance" parent="TextAppearance.MaterialComponents.Caption">
        <item name="android:textSize">14sp</item>
    </style>
    <style name="BottomNavigationViewTheme.TextAppearance_Selected" parent="TextAppearance.MaterialComponents.Caption">
        <item name="android:textSize">16sp</item>
    </style>

然后设置一把:可以啦。。没有水波纹啦。。头大。。

  <!--        底部导航栏BottomNavigationView-->
        <!--        BottomNavigationView-->
        <!--        app:itemBackground="@null"无效  用app:itemRippleColor="@null"-->
        <!--        app:itemIconSize="14dp"-->
        <com.google.android.material.bottomnavigation.BottomNavigationView
            android:id="@+id/ahb_bottomBNv"
            style="@style/BottomNavigationViewTheme"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/tablayout_bg_shape"
            app:itemHorizontalTranslationEnabled="false"
            app:itemTextColor="@drawable/bottom_text_selector"
            app:labelVisibilityMode="labeled"
            app:layout_constraintBottom_toBottomOf="parent">
        </com.google.android.material.bottomnavigation.BottomNavigationView>

2. 调整导航栏高度,以及图片文字间距,同时额外设置图片距离顶部一定高度,腾出空间放角标

2.1 我们要清楚 design_bottom_navigation_margin 是设置图片和文字的间距,但是底部导航栏默认高度是 56dp,所以你如果设置间距了margin,那么你的高度 design_bottom_navigation_height 请相应的margin,不然会重叠的。。

2.2 其次 design_bottom_navigation_icon_size 这个是可以调整图标尺寸,同样比如你大小为60dp,你的 design_bottom_navigation_height 也需要增加 60dp- 24dp, 因为图标默认是24,你相当于额外增加了高度,为了完整显示,请增加BottomNavigationView高度。 所以dimens覆写几个属性。。

 <resources>
    <!--    修改文字和图片的间距-->
    <dimen name="design_bottom_navigation_margin">4dp</dimen>
    <dimen name="design_bottom_navigation_icon_size">44dp</dimen>
    <!--    选中时的最大宽度-->
    <!--    <dimen name="design_bottom_navigation_active_item_max_width">168dp</dimen>-->
    <!--    未选中的最大宽度-->
    <!--    <dimen name="design_bottom_navigation_item_max_width">168dp</dimen>-->
    <!--    高度 默认的底部导航栏的高度是 56dp,我们增加间距4dp=60dp-->
    <dimen name="design_bottom_navigation_height">95dp</dimen>
</resources>

3. 注意,注意! 针对 2.2 提到的属性重写,其中我们要注意 design_bottom_navigation_margin,当我们设置高度比较高时,如果此时 design_bottom_navigation_margin还是4dp,那么结果是:你会发现图片和文字分离了,中间空了一定的高度。。

此时我们要增加design_bottom_navigation_margin的高度,相当于增加了icon距离顶部的间距, 看源码 :从下往下大概跟一下》。。。

最后我们发现其实当你 ahbBottomBNv .getMenu().getItem(position).setChecked( true );的时候,就会设置相关属性。 这个时候已经设置了icon的topMargin。。所以我们增加下design_bottom_navigation_margin即可。。 像网上描述的这个margin属性是图片和文字的间距,从目前粗浅的观摩源码来看是不改变默认属性的情况下是有效的。如果有更深入的理解,麻烦指教一下,谢谢。

4。 关于如何动态修改底部图标,采用动态从网络获取的方式,提供工具类就好了:

BottomNavigationViewHelper.java

package com.hl.base_module.util.bottomnavigation;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.google.android.material.bottomnavigation.BottomNavigationItemView;
import com.google.android.material.bottomnavigation.BottomNavigationMenuView;
import com.google.android.material.bottomnavigation.BottomNavigationView;
public class BottomNavigationViewHelper {
     * 设置图片尺寸
     * @param view
     * @param width
     * @param height
    public static void setImageSize(BottomNavigationView view, int width, int height) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
                ImageView imageView = item.findViewById(com.google.android.material.R.id.icon);
                final ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
                layoutParams.height = width;
                layoutParams.width = height;
                imageView.setLayoutParams(layoutParams);
        } catch (Exception e) {
            e.printStackTrace();
     * 设置Icon距离顶部高度
     * 不需要了,直接设置design_bottom_navigation_margin属性即可
     * @param view
     * @param marginTop
    public static void setImageMarginTop(BottomNavigationView view, int marginTop) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
                ImageView imageView = item.findViewById(com.google.android.material.R.id.icon);
                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) imageView.getLayoutParams();
                layoutParams.topMargin = marginTop;
                imageView.setLayoutParams(layoutParams);
        } catch (Exception e) {
            e.printStackTrace();
     * 设置Icon为网络图标
     * @param view
     * @param imgUrl
    public static void replaceItemImage(BottomNavigationView view, String[] imgUrl) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            for (int i = 0; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i);
                ImageView imageView = item.findViewById(com.google.android.material.R.id.icon);
                Glide.with(view.getContext())
                        .load(imgUrl[i])
                        .into(imageView);
        } catch (Exception e) {
            e.printStackTrace();
     * 设置Icon为刷新图标
     * @param view
     * @param gifUrl
    public static void replaceRefreshImage(BottomNavigationView view, int index, String gifUrl) {
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0);
        try {
            BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(index);
            ImageView imageView = item.findViewById(com.google.android.material.R.id.icon);
            Glide.with(view.getContext())
                    .load(gifUrl)
                    .into(imageView);
        } catch (Exception e) {
            e.printStackTrace();

4.1 使用:

new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                // 可以模拟请求成功后加载网络图标
                BottomNavigationViewHelper.replaceItemImage(getViewDataBinding().ahbBottomBNv,
                        new String[]{"https://file01.16sucai.com/d/file/2012/1023/20121023075322560.png",
                                "https://file01.16sucai.com/d/file/2012/1023/20121023075322530.png"});
        }, 5000);

4.2.1 还可以点击实现刷新图片,刷新结束后回归正常图片 - 加载一个gif

   // 底部菜单再次点击事件回调 - 这里我们可以做转圈刷新当前页面的效果
        getViewDataBinding().ahbBottomBNv.setOnNavigationItemReselectedListener(new BottomNavigationView.OnNavigationItemReselectedListener() {
            @Override
            public void onNavigationItemReselected(@NonNull MenuItem item) {
                // 再次点击首页,通知首页进行刷新
                EventBus.getDefault().post(new MessageEvent("再次点击刷新", "update_home"));
                BottomNavigationViewHelper.replaceRefreshImage(getViewDataBinding().ahbBottomBNv, 0, "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1589021367118&di=06f571cc13c0aca8f6b4afe85a328b24&imgtype=0&src=http%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20170914%2F6e33a4c4ff5d4ce2b6ce0cd8523c3733.gif");
        });

4.2.2 等刷新结束后,重新加载一个原来的图标即可 - 我用Eventbus做的通知哈。。可以其他方式

  /**
     * 收到刷新
     * @param messageEvent