Aandroid Design Support Library中增加了BottonNavigationView控件,实现底部导航切换页面方便了许多,同时它也有不便之处:

 1. 底部的条目数超过三个,点击每个条目是会有很大的偏移量2. 无法添加小红点提示

最终的效果图

1. 添加依赖(25以上)

implementation 'com.android.support:design:27.1.1'

2. xml布局使用

<layout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"><RelativeLayoutxmlns:app="http://schemas.android.com/apk/res-auto"android:clipChildren="false"android:layout_width="match_parent"android:layout_height="match_parent"><android.support.design.widget.BottomNavigationViewandroid:id="@+id/bottom_navigation"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:background="?android:attr/windowBackground"app:menu="@menu/navigation" /><com.zuoge.project.view.NoScrollViewPagerandroid:id="@+id/vp_main"android:layout_above="@id/bottom_navigation"android:layout_width="match_parent"android:layout_height="match_parent"/>
</RelativeLayout>
</layout>

其中有几个特有属性

1. app:itemBackground:指定底部导航栏的背景颜色,默认是当前的主题颜色
2. app:itemIconTint:指定底部导航栏元素图标的着色方式,默认元素选中是iocn颜色为@color/colorPrimary
3. app:itemTextColor:指定底部导航栏元素文字的着色方式
4. app:menu:使用Menu的形式为底部导航栏指定元素

使用menu属性定义底部条目:

1. 在res文件下创建menu文件夹
2. 在menu文件下创建条目的xml
3. 设置id、icon、title等属性
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@+id/menu"android:icon="@drawable/main_menu"android:title="@string/first" /><itemandroid:id="@+id/more"android:icon="@drawable/main_more"android:title="@string/more" /><itemandroid:id="@+id/information"android:icon="@drawable/main_information"android:title="@string/information" /><itemandroid:id="@+id/me"android:icon="@drawable/main_me"android:title="@string/me" />
</menu>

3. 代码实现

kotlin可以直接通过id获取到控件,不在使用findViewById获取控件

设置BottonNavigationView底部条目的点击监听

    bottom_navigation.setOnNavigationItemSelectedListener(mBottomNavigationView)

mBottomNavigationView

  private val mBottomNavigationView = BottomNavigationView.OnNavigationItemSelectedListener { item ->when (item.itemId) {R.id.menu -> {vp_main.currentItem = 0return@OnNavigationItemSelectedListener true}R.id.more -> {vp_main.currentItem = 1return@OnNavigationItemSelectedListener true}R.id.me -> {vp_main.currentItem = 2return@OnNavigationItemSelectedListener true}R.id.me2 -> {vp_main.currentItem = 3return@OnNavigationItemSelectedListener true}}false}

啊,不是我想要的效果,我想要的是4个item平分布局

4. 查看源码解决平分布局


进入到BottomNavigationMeunView

 @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {final int width = MeasureSpec.getSize(widthMeasureSpec);final int count = getChildCount();final int heightSpec = MeasureSpec.makeMeasureSpec(mItemHeight, MeasureSpec.EXACTLY);if (mShiftingMode) {final int inactiveCount = count - 1;final int activeMaxAvailable = width - inactiveCount * mInactiveItemMinWidth;final int activeWidth = Math.min(activeMaxAvailable, mActiveItemMaxWidth);final int inactiveMaxAvailable = (width - activeWidth) / inactiveCount;final int inactiveWidth = Math.min(inactiveMaxAvailable, mInactiveItemMaxWidth);int extra = width - activeWidth - inactiveWidth * inactiveCount;for (int i = 0; i < count; i++) {mTempChildWidths[i] = (i == mSelectedItemPosition) ? activeWidth : inactiveWidth;if (extra > 0) {mTempChildWidths[i]++;extra--;}}} else {final int maxAvailable = width / (count == 0 ? 1 : count);final int childWidth = Math.min(maxAvailable, mActiveItemMaxWidth);int extra = width - childWidth * count;for (int i = 0; i < count; i++) {mTempChildWidths[i] = childWidth;if (extra > 0) {mTempChildWidths[i]++;extra--;}}}int totalWidth = 0;for (int i = 0; i < count; i++) {final View child = getChildAt(i);if (child.getVisibility() == GONE) {continue;}child.measure(MeasureSpec.makeMeasureSpec(mTempChildWidths[i], MeasureSpec.EXACTLY),heightSpec);ViewGroup.LayoutParams params = child.getLayoutParams();params.width = child.getMeasuredWidth();totalWidth += child.getMeasuredWidth();}setMeasuredDimension(View.resolveSizeAndState(totalWidth,MeasureSpec.makeMeasureSpec(totalWidth, MeasureSpec.EXACTLY), 0),View.resolveSizeAndState(mItemHeight, heightSpec, 0));}

看到一个判断mShifingMode,这个变量控制是否平分布局


这里看到menu.size有一个判断,大于3是true,不大于是false

所以当iteam是大于3的时候,获取到mShifingMode设置为false,就可以平分了

由于BottomNavigationView无法通过代码直接来setShiftingMode的属性值(boolean类型),所以我们创建一个NavigationViewHelper并创建一个方法


class BottomNavigationViewHelper {companion object {@SuppressLint("RestrictedApi")open fun disableShiftMode(view: BottomNavigationView) {//获取子View BottomNavigationMenuView的对象val menuView = view.getChildAt(0) as BottomNavigationMenuViewtry {//设置私有成员变量mShiftingMode可以修改val shiftingMode = menuView.javaClass.getDeclaredField("mShiftingMode")shiftingMode.isAccessible = trueshiftingMode.setBoolean(menuView, false)shiftingMode.isAccessible = falsefor (i in 0 until menuView.childCount) {val item = menuView.getChildAt(i) as BottomNavigationItemView//去除shift效果item.setShiftingMode(false)item.setChecked(item.itemData.isChecked)}} catch (e: NoSuchFieldException) {} catch (e: IllegalAccessException) {}}}}

在Activity中使用

    bottom_navigation.setOnNavigationItemSelectedListener(mBottomNavigationView)//解决3个条目问题BottomNavigationViewHelper.disableShiftMode(bottom_navigation)


哼,这才是我想要的

5. BottomNavigationView+ViewPager

 private fun initView() {menuFragment = MenuFragment()moreFragment = MoreFragment()informationFragment = InformationFragment()meFragment = MeFragment()fragmentList.add(menuFragment!!)fragmentList.add(moreFragment!!)fragmentList.add(informationFragment!!)fragmentList.add(meFragment!!)normalAdapter = NormalAdapter(supportFragmentManager, fragmentList)vp_main.adapter = normalAdaptervp_main.offscreenPageLimit = fragmentList.sizevp_main.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {override fun onPageScrollStateChanged(state: Int) {}override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}override fun onPageSelected(position: Int) {if (menuItem != null) {menuItem!!.isChecked = false} else {bottom_navigation.getMenu().getItem(0).isChecked = false}menuItem = bottom_navigation.getMenu().getItem(position)menuItem!!.isChecked=true}})}internal inner class NormalAdapter(fm: FragmentManager, private val fragmentList: List<Fragment>) : FragmentPagerAdapter(fm) {override fun getItem(position: Int): Fragment {return fragmentList[position]}override fun getCount(): Int {return fragmentList.size}}


注意这里的 Fragment 包

import android.support.v4.app.Fragment

可以看到既可以点击item切换页面,也可以滑动切换页面
有时候项目需求不能滑动切换页面,好,我们来做下

6. 禁止ViewPager滑动

public class NoScrollViewPager extends ViewPager {private boolean noScroll = true;public NoScrollViewPager(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stub}public NoScrollViewPager(Context context) {super(context);}public void setNoScroll(boolean noScroll) {this.noScroll = noScroll;}@Overridepublic void scrollTo(int x, int y) {super.scrollTo(x, y);}@Overridepublic boolean onTouchEvent(MotionEvent arg0) {if (noScroll)return false;elsereturn super.onTouchEvent(arg0);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent arg0) {if (noScroll)return false;elsereturn super.onInterceptTouchEvent(arg0);}@Overridepublic void setCurrentItem(int item, boolean smoothScroll) {super.setCurrentItem(item, smoothScroll);}@Overridepublic void setCurrentItem(int item) {super.setCurrentItem(item, false);}}

然后修改xml

  <com.zuoge.project.view.NoScrollViewPagerandroid:id="@+id/vp_main"android:layout_width="match_parent"android:layout_height="match_parent"/>

这样就不能滑动切换了
在开发的时候,会经常遇到小红点的需求,像微信的聊天信息,新消息的通知
好,最后来实现下小红点

7. 添加小红点

BottomNavigationMenuView中的每一个Tab就是一个FrameLayout,所以我们可以在上面随意添加View、这样就可以实现角标了

     val menuView = bottom_navigation.getChildAt(0) as BottomNavigationMenuView//这里就是获取所添加的每一个Tab(或者叫menu),val tab = menuView.getChildAt(3)val itemView = tab as BottomNavigationItemView//加载角标View,新创建的一个布局val badge = LayoutInflater.from(this).inflate(R.layout.menu_badge, menuView, false)//添加到Tab上itemView.addView(badge)val count = badge.findViewById(R.id.tv_msg_count) as TextViewcount.text = 2.toString()//如果没有消息,不需要显示的时候那只需要将它隐藏即可//count.visibility = View.GONE

menu_badge.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:id="@+id/tv_msg_count"android:layout_width="16dp"android:layout_height="16dp"android:layout_gravity="center"android:layout_marginLeft="10dp"android:layout_marginTop="3dp"android:background="@drawable/bg_red_circle"android:gravity="center"android:textColor="@color/tool_title"android:textSize="12sp"/></LinearLayout>

demo下载

Kotlin中使用BottomNavigationView实现底部导航相关推荐

  1. Android Navigation与BottomNavigationView实现底部导航栏

    底部导航栏 一.效果图 二.实现 1.创建Fragment以及布局文件 2.添加FragmentContainerView和BottomNavigationView两个控件 3.配置xml资源文件 4 ...

  2. php点击切换图片的底部导航,如何优雅地使用BottomNavigationView实现底部导航栏+fragment切换效果...

    BottomNavigationView.jpeg 引言 之前总是使用RadioButton+ViewPager来实现底部导航栏+fragment切换效果,总是繁琐地还需要写ViewPager的适配器 ...

  3. android radiobutton底部导航,android中Fragment+RadioButton实现底部导航栏

    在App中经常看到这样的tab底部导航栏 那么这种效果是如何实现,实现的方式有很多种,最常见的就是使用Fragment+RadioButton去实现.下面我们来写一个例子 首先我们先在activity ...

  4. vue中使用transition标签底部导航闪烁问题

    <transition :name="transitionName" :duration="{ enter: 500, leave: 0 }" > ...

  5. hbuilderx 底部_如何在Hbuilder中制作app底部导航栏

    . 1 问题描述 最近在使用Hbuilder进行移动app前端开发中,我通常搭建首页框架的常规方法是在index.html主文件中使用多种框架组件模块,再通过css叠层样式表对相应模块加以修饰.但在分 ...

  6. android底部导航栏_Kotlin实现底部导航栏

    在我们开发app过程中,免不了使用底部导航栏,所以今天我们就来看看怎么样用kotlin实现底部导航栏. 新建项目 新建一个KotlinBottomNavigationDemo项目. 在gradle中添 ...

  7. Android开发笔记(一百六十九)利用BottomNavigationView实现底部标签栏

    在Android Studio上创建官方默认的首屏标签页面很方便,首先右击需要添加标签栏的模块,在弹出的右键菜单中依次选择"New"--"Activity"-- ...

  8. 21天学习之二(Android 10.0 SystemUI默认去掉底部导航栏的三种方法)

    活动地址:CSDN21天学习挑战赛 1.概述 在定制化开发中,在SystemUI的一些定制功能中,针对默认去掉底部导航栏的方法有好几种,StatusBar和DisplayPolicy.java中api ...

  9. Android---简易的底部导航栏

    目录 一.activity_main.xml布局 二.给ViewPager2 创建适配器 三.ViewPager2 数据源 四.MainActivity.java类 1.初始化数据源. 2.ViewP ...

  10. Flutter 项目实战 底部导航 六

    / 生活中常部分app底部导航样式 / 从智能手机的普及我们的生活 , 手机已经为我们生活提供了方便 . 购买手机后系统默认安装了很多款app , 随便点开一款手机app 进入应用首页映入眼帘的就是底 ...

最新文章

  1. git通过authorized_keys来管理用户的权限(二)
  2. SSL/TLS协议运行机制
  3. Hadoop1.9安装配置
  4. 内容管理系统(CMS)的设计和选型
  5. 谷歌、IBM 们的“量子争霸”迷局
  6. 双系统安装:Deepin 尝鲜
  7. 计算机财务应用实验心得,金蝶财务软件实训心得.doc
  8. 计算机进入bios,详细教您电脑怎么进入bios
  9. python close函数_Python math.isclose() 方法
  10. 华为推出打车平台 Petal,科技大厂再战聚合打车
  11. 对接熊迈SDK工作记录之集成准备
  12. 关于U盘烧录iso问题
  13. access查询两列信息合并输出_如何在Access中合并两个数据表中的数据
  14. Android使用Fragment打造万能页面切换框架(三)
  15. linux ssh 终端退格键,退格键,Tab,Del和箭头键在终端中不起作用(使用ssh)
  16. http状态返回代码 1xx(临时响应)
  17. Android开发之漫漫长途 XII——Fragment 详解
  18. 文件内容快速收索工具(Listary)
  19. SolidWorks模型导入Matlab接口设置的创建
  20. input框 限制输入数字或英文的正则表达式

热门文章

  1. 网站建设--报刊订阅管理系统(java+html)(课程设计)内置部分代码和截图,资源库中有该资源
  2. 为什么要考华为云认证?有什么用?
  3. 一个懒鬼胡乱写的多解
  4. 第十七周博客作业西北师范大学|李晓婷
  5. 【Leetcode刷题Python】739. 每日温度
  6. Linux中cd会进入什么位置,linux命令中cd/和cd命令是什么意思
  7. CI/CD的简介以及区别
  8. 分享一些java学习网站网址
  9. 英文大写字母A~Z,小写字母a~z对应的ASCII码快速查询
  10. shared_ptr中的owner_before解析(最易懂,最全面)