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

722 阅读4分钟

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

  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 - 其他属性也一并贴出

<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-->
    <!--        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>
  1. 调整导航栏高度,以及图片文字间距,同时额外设置图片距离顶部一定高度,腾出空间放角标

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覆写几个属性。。

4dp 44dp 95dp 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
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void updateRefreshFinish(MessageEvent messageEvent) {
        if (messageEvent.getObject().equals("update_home_finish")) {
            BottomNavigationViewHelper.replaceRefreshImage(getViewDataBinding().ahbBottomBNv, 0, "https://file01.16sucai.com/d/file/2012/1023/20121023075322560.png");
        }
    }

基本上差不多了。总体效果

工程地址(对了角标就是自定义了一个Textview,在librarys/lib_miniui模块下面):github.com/FanChael/MV… 欢迎一起学习讨论指教,谢谢star...我是打算继续完善,未来用来做模板工程。太多细节要处理了。另外很多类似商场首页效果还没来得及搞。。