分享

底部菜单控件BottomNavigationView的使用

 hncdman 2022-05-10 发布于湖南省

置顶

小凡特爱写代码

已于 2022-03-31 00:46:49 修改

3929

 收藏 22

分类专栏: MaterialDesign 文章标签: 底部导航栏 BottomNav 安卓库控件

版权

MaterialDesign

专栏收录该内容

5 篇文章0 订阅

订阅专栏

BottomNavigationView实现底部导航栏的整体效果如下图所示:

BottomNavigationView

引入包最新

基本使用

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

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

完整的MainActivity代码

app:labelVisibilityMode=""属性

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

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

设置水波纹效果 app:itemRippleColor

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

除去自带着色效果

创建一个drawable选择器

设置相应item中android:icon属性

添加一个消息提示红色点

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

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

引入包最新

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

1

基本使用

    <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" />

1

2

3

4

5

6

7

8

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./apk/res/android"

    xmlns:app="http://schemas./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>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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

<?xml version="1.0" encoding="utf-8"?>

<selector xmlns:android="http://schemas./apk/res/android">

    <item android:color="#b8b9bd" android:state_checked="false" />

    <item android:color="#0fbbbb" android:state_checked="true" />

</selector>

1

2

3

4

5

完整的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();

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

运行的效果图如下:

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;

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

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

        app:itemTextAppearanceActive="@style/selectText"//选中字体大小风格,

        app:itemTextAppearanceInactive="@style/unSelectText"//未选中字体大小风格

1

2

<?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>

1

2

3

4

5

6

7

8

9

10

11

12

13

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

    <!-- 导航栏高度 -->

    <dimen name="design_bottom_navigation_height">80dp</dimen>

1

2

设置了这个之后导航栏高度就变高了,同时图片和文字之间的距离就变大了,具体是多少我也不清楚

其他的设置都是瞎搞;

设置水波纹效果 app:itemRippleColor

先说一下这里的 app:itemBackground 和app:itemRippleColor都是设置给到导航栏的背景

如果要设置水波纹有有效果,那么必须不设置背景:

 app:itemBackground="@null"

 app:itemRippleColor="@color/design_default_color_primary"

1

2

只有这样才会有效果;否则无效;

这是在其源码里面发现的:

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

    }

1

2

3

4

5

6

7

8

9

再看看 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);

      }

    }

  }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

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

想要切换自己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./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>

1

2

3

4

5

设置相应item中android:icon属性

找到相应item中 android:icon属性

<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas./apk/res/android"

    xmlns:app="http://schemas./apk/res-auto">

    <item

        android:id="@+id/action_circle"

        android:icon="@drawable/sl_drawable_circle"

        android:title="@string/circle" />

</menu>

1

2

3

4

5

6

7

8

第二个中的切换都是原始图片的切换;

以上就是总结的全部内容了;欢迎评论和点赞,交流,互相学习了!

添加一个消息提示红色点

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

        //获取整个的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);

1

2

3

4

5

6

7

8

9

10

11

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

        //添加消息红点第二种方式

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

            }

        });

————————————————

版权声明:本文为CSDN博主「小凡特爱写代码」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/eyishion/article/details/112688387

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多