Kotlin中使用BottomNavigationView实现底部导航
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实现底部导航相关推荐
- Android Navigation与BottomNavigationView实现底部导航栏
底部导航栏 一.效果图 二.实现 1.创建Fragment以及布局文件 2.添加FragmentContainerView和BottomNavigationView两个控件 3.配置xml资源文件 4 ...
- php点击切换图片的底部导航,如何优雅地使用BottomNavigationView实现底部导航栏+fragment切换效果...
BottomNavigationView.jpeg 引言 之前总是使用RadioButton+ViewPager来实现底部导航栏+fragment切换效果,总是繁琐地还需要写ViewPager的适配器 ...
- android radiobutton底部导航,android中Fragment+RadioButton实现底部导航栏
在App中经常看到这样的tab底部导航栏 那么这种效果是如何实现,实现的方式有很多种,最常见的就是使用Fragment+RadioButton去实现.下面我们来写一个例子 首先我们先在activity ...
- vue中使用transition标签底部导航闪烁问题
<transition :name="transitionName" :duration="{ enter: 500, leave: 0 }" > ...
- hbuilderx 底部_如何在Hbuilder中制作app底部导航栏
. 1 问题描述 最近在使用Hbuilder进行移动app前端开发中,我通常搭建首页框架的常规方法是在index.html主文件中使用多种框架组件模块,再通过css叠层样式表对相应模块加以修饰.但在分 ...
- android底部导航栏_Kotlin实现底部导航栏
在我们开发app过程中,免不了使用底部导航栏,所以今天我们就来看看怎么样用kotlin实现底部导航栏. 新建项目 新建一个KotlinBottomNavigationDemo项目. 在gradle中添 ...
- Android开发笔记(一百六十九)利用BottomNavigationView实现底部标签栏
在Android Studio上创建官方默认的首屏标签页面很方便,首先右击需要添加标签栏的模块,在弹出的右键菜单中依次选择"New"--"Activity"-- ...
- 21天学习之二(Android 10.0 SystemUI默认去掉底部导航栏的三种方法)
活动地址:CSDN21天学习挑战赛 1.概述 在定制化开发中,在SystemUI的一些定制功能中,针对默认去掉底部导航栏的方法有好几种,StatusBar和DisplayPolicy.java中api ...
- Android---简易的底部导航栏
目录 一.activity_main.xml布局 二.给ViewPager2 创建适配器 三.ViewPager2 数据源 四.MainActivity.java类 1.初始化数据源. 2.ViewP ...
- Flutter 项目实战 底部导航 六
/ 生活中常部分app底部导航样式 / 从智能手机的普及我们的生活 , 手机已经为我们生活提供了方便 . 购买手机后系统默认安装了很多款app , 随便点开一款手机app 进入应用首页映入眼帘的就是底 ...
最新文章
- git通过authorized_keys来管理用户的权限(二)
- SSL/TLS协议运行机制
- Hadoop1.9安装配置
- 内容管理系统(CMS)的设计和选型
- 谷歌、IBM 们的“量子争霸”迷局
- 双系统安装:Deepin 尝鲜
- 计算机财务应用实验心得,金蝶财务软件实训心得.doc
- 计算机进入bios,详细教您电脑怎么进入bios
- python close函数_Python math.isclose() 方法
- 华为推出打车平台 Petal,科技大厂再战聚合打车
- 对接熊迈SDK工作记录之集成准备
- 关于U盘烧录iso问题
- access查询两列信息合并输出_如何在Access中合并两个数据表中的数据
- Android使用Fragment打造万能页面切换框架(三)
- linux ssh 终端退格键,退格键,Tab,Del和箭头键在终端中不起作用(使用ssh)
- http状态返回代码 1xx(临时响应)
- Android开发之漫漫长途 XII——Fragment 详解
- 文件内容快速收索工具(Listary)
- SolidWorks模型导入Matlab接口设置的创建
- input框 限制输入数字或英文的正则表达式
热门文章
- 网站建设--报刊订阅管理系统(java+html)(课程设计)内置部分代码和截图,资源库中有该资源
- 为什么要考华为云认证?有什么用?
- 一个懒鬼胡乱写的多解
- 第十七周博客作业西北师范大学|李晓婷
- 【Leetcode刷题Python】739. 每日温度
- Linux中cd会进入什么位置,linux命令中cd/和cd命令是什么意思
- CI/CD的简介以及区别
- 分享一些java学习网站网址
- 英文大写字母A~Z,小写字母a~z对应的ASCII码快速查询
- shared_ptr中的owner_before解析(最易懂,最全面)