BottomNavigationView实现底部导航栏

BottomNavigationView是一个底部导航栏控件,它item只有3~5个一般和fragment一起结合使用。就像下图这样,这里对它的使用做一个笔记方便以后查阅。


在这里插入图片描述

引入包最新

 implementation 'com.google.android.material:material:1.2.0-alpha06'

基本使用

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:itemBackground="@color/white"
        app:itemIconTint="@color/sl_color_green_grey"
        app:itemTextColor="@color/sl_color_green_grey"
        app:menu="@menu/menu_navigation_fix" />

BottomNavigationView控件的主要属性含义:

  • app:iteamBackground 指的是底部导航栏的背景颜色,默认是主题的颜色
  • app:itemIconTint 指的是底部导航栏中图片的颜色
  • app:itemTextColor 指的是底部导航栏文字的颜色
  • app:menu 指的是菜单布局(文字和图片都写在这个里面)

app:menu="@menu/menu_navigation_fix"中的界面

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_message"
        android:checked="true"
        android:icon="@mipmap/icon_message"
        android:title="@string/message" />
    <item
        android:id="@+id/action_find"
        android:icon="@mipmap/icon_find"
        android:title="@string/find" />
    <item
        android:id="@+id/action_circle"
        android:icon="@mipmap/icon_circle"
        android:title="@string/circle" />
</menu>

控件点击时候颜色选择@color/sl_color_green_grey

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="#b8b9bd" android:state_checked="false" />
    <item android:color="#0fbbbb" android:state_checked="true" />
</selector>

完整的MainActivity代码

public class MainActivity extends AppCompatActivity {

    private FrameLayout mainFrame;
    private BottomNavigationView bottomNavigation;
    private MyFragment messageFragment, findFragment, circleFragment;
    private Fragment[] fragments;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        messageFragment = new MyFragment();
        messageFragment.setMessage(getResources().getString(R.string.message));
        findFragment = new MyFragment();
        findFragment.setMessage(getResources().getString(R.string.find));
        circleFragment = new MyFragment();
        circleFragment.setMessage(getResources().getString(R.string.circle));
        fragments = new Fragment[]{messageFragment, findFragment, circleFragment};
        mainFrame = findViewById(R.id.mainContainer);
        //设置fragment到布局
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.mainContainer, messageFragment)
                .commit();

        bottomNavigation = findViewById(R.id.navigation);
        //这里是bottomnavigationview的点击事件
        bottomNavigation.setOnNavigationItemSelectedListener(listener);
    }

    private BottomNavigationView.OnNavigationItemSelectedListener listener
            = new BottomNavigationView.OnNavigationItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            int id = item.getItemId();
            if (id == R.id.action_message) switchFragment(fragments[0]);
            else if (id == R.id.action_find) switchFragment(fragments[1]);
            else if (id == R.id.action_circle) switchFragment(fragments[2]);
            return true;
        }
    };

    // 切换fragment
    private void switchFragment(Fragment fragment) {
        FragmentManager fm = getSupportFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        transaction.replace(R.id.mainContainer, fragment);
        transaction.commitAllowingStateLoss();
    }

}

运行的效果图如下:
在这里插入图片描述

app:labelVisibilityMode=""属性

item多的时候,指的是item非选中状态显示文字,有以下几个值:

  • labeled 图标文字都显示
  • selected
  • auto
  • unlabeled 文字不显示

它们依次运行如下图所示
在这里插入图片描述
auto和select和i 属性sShifting有关
此时isShifting=true;你会发现auto和 selected的效果是一样的效果;
当isShifting=false时候,auto和lable是一样的效果;
关键是这个isShift属性没法设置,目前只有设置2个item的时候它们才好区别;感觉auto这个属性有点鸡肋;下面贴一下关键的源码:

switch (labelVisibilityMode) {
      case LabelVisibilityMode.LABEL_VISIBILITY_AUTO:
        if (isShifting) {
          if (checked) {
            setViewLayoutParams(icon, defaultMargin, Gravity.CENTER_HORIZONTAL | Gravity.TOP);
            setViewValues(largeLabel, 1f, 1f, VISIBLE);
          } else {
            setViewLayoutParams(icon, defaultMargin, Gravity.CENTER);
            setViewValues(largeLabel, 0.5f, 0.5f, INVISIBLE);
          }
          smallLabel.setVisibility(INVISIBLE);
        } else {
          if (checked) {
            setViewLayoutParams(
                icon, (int) (defaultMargin + shiftAmount), Gravity.CENTER_HORIZONTAL | Gravity.TOP);
            setViewValues(largeLabel, 1f, 1f, VISIBLE);
            setViewValues(smallLabel, scaleUpFactor, scaleUpFactor, INVISIBLE);
          } else {
            setViewLayoutParams(icon, defaultMargin, Gravity.CENTER_HORIZONTAL | Gravity.TOP);
            setViewValues(largeLabel, scaleDownFactor, scaleDownFactor, INVISIBLE);
            setViewValues(smallLabel, 1f, 1f, VISIBLE);
          }
        }
        break;

字体的style-可以设置字体大小

在这里插入图片描述

        app:itemTextAppearanceActive="@style/selectText"//选中字体大小风格,
        app:itemTextAppearanceInactive="@style/unSelectText"//未选中字体大小风格
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="selectText">
        <item name="android:textSize">20sp</item>
        <item name="android:drawablePadding">8dp</item>
    </style>

    <style name="unSelectText">
        <item name="android:textSize">14sp</item>
        <item name="android:drawablePadding">4dp</item>
    </style>
</resources>

导航栏高度和文字和图片之间的间距

    <!-- 导航栏高度 -->
    <dimen name="design_bottom_navigation_height">80dp</dimen>

设置了这个之后导航栏高度就变高了,同时图片和文字之间的距离就变大了,具体是多少我也不清楚
其他的设置都是瞎搞;
在这里插入图片描述

设置水波纹效果 app:itemRippleColor

在这里插入图片描述

先说一下这里的 app:itemBackgroundapp:itemRippleColor都是设置给到导航栏的背景
如果要设置水波纹有有效果,那么必须不设置背景:

 app:itemBackground="@null"
 app:itemRippleColor="@color/design_default_color_primary"

只有这样才会有效果;否则无效;
这是在其源码里面发现的:

    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);
    }

再看看 setItemRippleColor(itemRippleColor);方法,最后还是把水波纹效果设置给了 menuView.setItemBackgroundRes();

  public void setItemRippleColor(@Nullable ColorStateList itemRippleColor) {
    if (this.itemRippleColor == itemRippleColor) {
      // Clear the item background when setItemRippleColor(null) is called for consistency.
      if (itemRippleColor == null && menuView.getItemBackground() != null) {
        menuView.setItemBackground(null);
      }
      return;
    }

    this.itemRippleColor = itemRippleColor;
    if (itemRippleColor == null) {
      menuView.setItemBackground(null);
    } else {
      ColorStateList rippleDrawableColor =
          RippleUtils.convertToRippleDrawableColor(itemRippleColor);
      if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
        menuView.setItemBackground(new RippleDrawable(rippleDrawableColor, null, null));
      } else {
        GradientDrawable rippleDrawable = new GradientDrawable();
        // TODO: Find a workaround for this. Currently on certain devices/versions, LayerDrawable
        // will draw a black background underneath any layer with a non-opaque color,
        // (e.g. ripple) unless we set the shape to be something that's not a perfect rectangle.
        rippleDrawable.setCornerRadius(0.00001F);
        Drawable rippleDrawableCompat = DrawableCompat.wrap(rippleDrawable);
        DrawableCompat.setTintList(rippleDrawableCompat, rippleDrawableColor);
        menuView.setItemBackground(rippleDrawableCompat);
      }
    }
  }

切换自己设定选中图片和未选中图片

想要切换自己UI设计师给的两种不同的Ui图片;

除去自带着色效果

navigation.setItemIconTintList(null) 除去自带着色效果 (在XML中app:itemIconTint=@null无效,需要代码设置)

创建一个drawable选择器

有几个item就创建几个,比如sl_drawable_circle.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="false" android:drawable="@mipmap/icon_circle"/>
    <item android:state_checked="true" android:drawable="@mipmap/icon_circle_focus"/>
</selector>

设置相应item中android:icon属性

找到相应item中 android:icon属性

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_circle"
        android:icon="@drawable/sl_drawable_circle"
        android:title="@string/circle" />
</menu>

在这里插入图片描述
第二个中的切换都是原始图片的切换;
以上就是总结的全部内容了;欢迎评论和点赞,交流,互相学习了!

添加一个消息提示红色点

第一种方式粗略的添加方式

在这里插入图片描述

        //获取整个的NavigationView
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigation.getChildAt(0);
        //这里就是获取所添加的每一个Tab(或者叫menu),
        View tab = menuView.getChildAt(0);
        BottomNavigationItemView itemView = (BottomNavigationItemView) tab;
        //加载我们的角标View,新创建的一个布局
        View badge = LayoutInflater.from(this).inflate(R.layout.item_red_dot, menuView, false);
        //添加到Tab上
        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(badge.getLayoutParams());
        lp.gravity = Gravity.TOP | Gravity.END;
        itemView.addView(badge, lp);

第二种(消息红色的中心放在图片右上角顶点)

在这里插入图片描述

        //添加消息红点第二种方式
        BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigation.getChildAt(0);
        View tab = menuView.getChildAt(0);
        BottomNavigationItemView itemView = (BottomNavigationItemView) tab;
        //从系统里面获取图标的ImageView
        ImageView iv = itemView.findViewById(R.id.icon);
        //加载我们的角标View,新创建的一个布局
        final View badge = LayoutInflater.from(this).inflate(R.layout.item_red_dot, menuView, false);
        final FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(badge.getLayoutParams());
        //等到有高度以后在布局
        iv.post(new Runnable() {
            @Override
            public void run() {
                lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
                lp.topMargin = iv.getTop() - lp.height / 2;//图片top - 消息点的高度一半
                lp.leftMargin = iv.getWidth() / 2;//图片的宽度的一半
                itemView.addView(badge, lp);
            }
        });

猜你喜欢

转载自blog.csdn.net/eyishion/article/details/112688387