Android底部导航栏的三种风格实现

2023-11-12

一、效果图展示

如果动图没有动的话,也可以看下面这个静态图

以下挨个分析每个的实现,这里只做简单的效果展示,大家可以基于目前代码做二次开发。

二、BottomNavigationView

这是 Google 给我们提供的一个专门用于底部导航的 View,你只需要在新建 Activity 的时候选择 “Bottom Navigation Activity”,IDE 就会自动使用 BottomNavigationView 帮你生成好相应的代码了。

1. 在 xml 中使用

 <android.support.design.widget.BottomNavigationView
    android:id="@+id/navigation"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginEnd="0dp"
    android:layout_marginStart="0dp"
    android:background="?android:attr/windowBackground"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:menu="@menu/navigation" / 

这里面唯一要注意的就是 app:menu 属性了,它指定了你的导航栏显示的页面菜单是怎样的。

2. menu 的布局文件

<?xml version="1.0" encoding="utf-8"? 
<menu xmlns:android="http://schemas.android.com/apk/res/android" 
 
  <item
    android:id="@+id/navigation_home"
    android:icon="@drawable/ic_home_black_24dp"
    android:title="@string/title_home" / 
 
  <item
    android:id="@+id/navigation_dashboard"
    android:icon="@drawable/ic_dashboard_black_24dp"
    android:title="@string/title_dashboard" / 
 
  <item
    android:id="@+id/navigation_notifications"
    android:icon="@drawable/ic_notifications_black_24dp"
    android:title="@string/title_notifications" / 
 
</menu 

3. 在 Activity 中调用

 private TextView mTextMessage;
 
  private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
      = new BottomNavigationView.OnNavigationItemSelectedListener() {
 
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
      switch (item.getItemId()) {
        case R.id.navigation_home:
          mTextMessage.setText(R.string.title_home);
          return true;
        case R.id.navigation_dashboard:
          mTextMessage.setText(R.string.title_dashboard);
          return true;
        case R.id.navigation_notifications:
          mTextMessage.setText(R.string.title_notifications);
          return true;
      }
      return false;
    }
  };
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_style1);
 
    mTextMessage = findViewById(R.id.message);
    BottomNavigationView navigation = findViewById(R.id.navigation);
    navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
  }

这里的演示 code 都是 IDE 自动生成的,由于 BottomNavigationView 目前我还没有在项目中实际使用过,这里不做过多分析,使用起来不难,以上代码已经足以满足我们的基本使用要求了。

三、RadioGroup + ViewPager

这是一种比较常见了的,下面 4 个 tab 的导航按钮,可以切换不同的页面,这里页面使用了 ViewPager + Fragment 的组合,实现了滑动的页面效果,也可以不使用 ViewPager,这个根据产品的定义来使用即可。

1. 布局文件

<?xml version="1.0" encoding="utf-8"? 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".style2.Style2Activity" 
 
  <android.support.v4.view.ViewPager
    android:id="@+id/fragment_vp"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_above="@+id/tabs_rg" / 
 
  <RadioGroup
    android:id="@+id/tabs_rg"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    android:layout_alignParentBottom="true"
    android:background="#dcdcdc"
    android:orientation="horizontal" 
 
    <RadioButton
      android:id="@+id/today_tab"
      style="@style/Custom.TabRadioButton"
      android:checked="true"
      android:drawableTop="@drawable/tab_sign_selector"
      android:text="今日" / 
 
    <RadioButton
      android:id="@+id/record_tab"
      style="@style/Custom.TabRadioButton"
      android:drawableTop="@drawable/tab_record_selector"
      android:text="记录" / 
 
    <RadioButton
      android:id="@+id/contact_tab"
      style="@style/Custom.TabRadioButton"
      android:drawableTop="@drawable/tab_contact_selector"
      android:text="通讯录" / 
 
    <RadioButton
      android:id="@+id/settings_tab"
      style="@style/Custom.TabRadioButton"
      android:drawableTop="@drawable/tab_setting_selector"
      android:text="设置" / 
  </RadioGroup 
</RelativeLayout 

2. Activity 类

public class Style2Activity extends AppCompatActivity {
 
  private ViewPager mViewPager;
  private RadioGroup mTabRadioGroup;
 
  private List<Fragment  mFragments;
  private FragmentPagerAdapter mAdapter;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_style2);
    initView();
  }
 
  private void initView() {
    // find view
    mViewPager = findViewById(R.id.fragment_vp);
    mTabRadioGroup = findViewById(R.id.tabs_rg);
    // init fragment
    mFragments = new ArrayList< (4);
    mFragments.add(BlankFragment.newInstance("今日"));
    mFragments.add(BlankFragment.newInstance("记录"));
    mFragments.add(BlankFragment.newInstance("通讯录"));
    mFragments.add(BlankFragment.newInstance("设置"));
    // init view pager
    mAdapter = new MyFragmentPagerAdapter(getSupportFragmentManager(), mFragments);
    mViewPager.setAdapter(mAdapter);
    // register listener
    mViewPager.addOnPageChangeListener(mPageChangeListener);
    mTabRadioGroup.setOnCheckedChangeListener(mOnCheckedChangeListener);
  }
 
  @Override
  protected void onDestroy() {
    super.onDestroy();
    mViewPager.removeOnPageChangeListener(mPageChangeListener);
  }
 
  private ViewPager.OnPageChangeListener mPageChangeListener = new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
 
    }
 
    @Override
    public void onPageSelected(int position) {
      RadioButton radioButton = (RadioButton) mTabRadioGroup.getChildAt(position);
      radioButton.setChecked(true);
    }
 
    @Override
    public void onPageScrollStateChanged(int state) {
 
    }
  };
 
  private RadioGroup.OnCheckedChangeListener mOnCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
      for (int i = 0; i < group.getChildCount(); i++) {
        if (group.getChildAt(i).getId() == checkedId) {
          mViewPager.setCurrentItem(i);
          return;
        }
      }
    }
  };
 
  private class MyFragmentPagerAdapter extends FragmentPagerAdapter {
 
    private List<Fragment  mList;
 
    public MyFragmentPagerAdapter(FragmentManager fm, List<Fragment  list) {
      super(fm);
      this.mList = list;
    }
 
    @Override
    public Fragment getItem(int position) {
      return this.mList == null ? null : this.mList.get(position);
    }
 
    @Override
    public int getCount() {
      return this.mList == null ? 0 : this.mList.size();
    }
  }
 
}

这里唯一注意点的就是两个监听事件,要实现底部导航按钮和页面的联动。

四、带页面跳转功能的底部导航

很多 APP 的底部导航栏中间有一个很大的按钮,点击后通常是打开一个新的页面,这里我们要实现的就是这种底部导航。 依旧是使用 RadioGroup 来做,只不过中间一个 tab 我们先用一个空的 View 来占位,然后在这个 View 的位置放置一个较大的按钮来覆盖住。

1. 布局文件

<?xml version="1.0" encoding="utf-8"? 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".style3.Style3Activity" 
 
  <FrameLayout
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_above="@+id/tabs_rg" / 
 
  <RadioGroup
    android:id="@+id/tabs_rg"
    android:layout_width="match_parent"
    android:layout_height="56dp"
    android:layout_alignParentBottom="true"
    android:background="#dcdcdc"
    android:orientation="horizontal" 
 
    <RadioButton
      android:id="@+id/today_tab"
      style="@style/Custom.TabRadioButton"
      android:checked="true"
      android:drawableTop="@drawable/tab_sign_selector"
      android:text="今日" / 
 
    <RadioButton
      android:id="@+id/record_tab"
      style="@style/Custom.TabRadioButton"
      android:drawableTop="@drawable/tab_record_selector"
      android:text="记录" / 
 
    <View style="@style/Custom.TabRadioButton" / 
 
    <RadioButton
      android:id="@+id/contact_tab"
      style="@style/Custom.TabRadioButton"
      android:drawableTop="@drawable/tab_contact_selector"
      android:text="通讯录" / 
 
    <RadioButton
      android:id="@+id/settings_tab"
      style="@style/Custom.TabRadioButton"
      android:drawableTop="@drawable/tab_setting_selector"
      android:text="设置" / 
  </RadioGroup 
 
  <ImageView
    android:id="@+id/sign_iv"
    android:layout_width="80dp"
    android:layout_height="80dp"
    android:layout_alignParentBottom="true"
    android:layout_centerHorizontal="true"
    android:background="@android:color/transparent"
    android:src="@mipmap/sign" / 
</RelativeLayout 

2. Activity 类

public class Style3Activity extends AppCompatActivity {
 
  private RadioGroup mTabRadioGroup;
  private SparseArray<Fragment  mFragmentSparseArray;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_style3);
    initView();
  }
 
  private void initView() {
    mTabRadioGroup = findViewById(R.id.tabs_rg);
    mFragmentSparseArray = new SparseArray< ();
    mFragmentSparseArray.append(R.id.today_tab, BlankFragment.newInstance("今日"));
    mFragmentSparseArray.append(R.id.record_tab, BlankFragment.newInstance("记录"));
    mFragmentSparseArray.append(R.id.contact_tab, BlankFragment.newInstance("通讯录"));
    mFragmentSparseArray.append(R.id.settings_tab, BlankFragment.newInstance("设置"));
    mTabRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
      @Override
      public void onCheckedChanged(RadioGroup group, int checkedId) {
        // 具体的fragment切换逻辑可以根据应用调整,例如使用show()/hide()
        getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
            mFragmentSparseArray.get(checkedId)).commit();
      }
    });
    // 默认显示第一个
    getSupportFragmentManager().beginTransaction().add(R.id.fragment_container,
        mFragmentSparseArray.get(R.id.today_tab)).commit();
    findViewById(R.id.sign_iv).setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        startActivity(new Intent(Style3Activity.this, SignActivity.class));
      }
    });
  }
 
}

注意:

如果这里你也想使用 ViewPager 来展示 Fragment 的话,一定要注意这里的 RadioGroup 中间有一个占位的 View,即两者的监听事件里,实现联动时要考虑多个这个 View 的存在。更多教程请访问码农之家  

代码地址: https://gitee.com/afei_/BottomTabbar

到此这篇关于Android底部导航栏的三种风格实现的文章就介绍到这了,更多相关Android底部导航栏内容请搜索ZaLou.Cn以前的文章或继续浏览下面的相关文章希望大家以后多多支持ZaLou.Cn!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android底部导航栏的三种风格实现 的相关文章

  • 您的应用中的 Google Analytics SDK

    我按照这里的说明进行操作 https developers google com analytics devguides collection android v3 https developers google com analytics
  • Kotlin Android Firebase 数据库哈希映射转换为类

    我正在尝试从 firebase 数据库获取数据 断点显示它正在获取数据 但看起来我没有正确地将其分配给我的班级 这会导致此异常 java lang ClassCastException 无法将 java util HashMap 转换为 班
  • 服务如何在后台运行 - Android

    今天的采访中我被问到了这个问题 什么是服务 我对此的回答是 Service 是 Android 的基本组件 它没有 UI 并且在后台运行 Service 是否在主线程上运行 不 那么它是如何在后台运行的呢 我心里一片空白 有人可以解释一下如
  • ndk-build error.opencv2/core/core.hpp:没有这样的文件或目录

    我在 Android 中使用 OpenCV Nonfree 模块时遇到问题 我读了这个教程https sites google com site wghsite technical notes sift surf opencv androi
  • 清晰的图标 清晰的 Android 应用程序

    你好 下午好 关于如何提高图标的 png 质量 有什么想法吗 我使用了 Android 开发者页面上的套件 但我无法获得清晰的图像 我的意思是非常清晰 我是否需要以不同的方式加载此图标 而不仅仅是拖入我的布局 谢谢 我使用这个布局
  • Android 中图像字节表示的每像素字节数

    我目前正在编写一个Android应用程序 需要在其中使用OCR 为了实现这一点 我将 Tesseract 与tesseract android tools 项目 http code google com p tesseract androi
  • 如何在 Android 中创建始终位于顶部的全屏覆盖 Activity

    我希望能够创建一个始终位于 Android 显示前面的 Activity 它不应该接收任何输入 只需将其传递到其下面的任何应用程序即可 像平视显示器之类的东西 我能够研究我需要将底层窗口类型设置为 TYPE SYSTEM ALERT 但看起
  • 将项目添加到 android 框架的设置中

    我正在 android 框架中工作 我想向 android 操作系统中的现有设置添加一个项目 您能告诉我如何执行此操作吗 首先阅读有关偏好活动 http developer android com reference android pre
  • 将清除会话标志设置为 FALSE 后,我丢失了已发布的值

    有人有一个合乎逻辑的解释为什么尽管我有clear session flage false当我未连接到经纪商时 我没有收到我订阅的更新的已发布消息 将 aore提到的标志设置为 false 后 我运行了我的应用程序 并且我不断向主题发布一些值
  • 使用 RoboSpice 有没有办法从异常中获取 HTTP 错误代码?

    我正在编写一个使用 RoboSpice 的应用程序 在请求侦听器 onRequestFailure SpiceException arg0 中 有没有办法确定该错误是由于发生 401 HTTP 错误而导致的 我有一个后端服务 当令牌过期时
  • Android Studio APK META-INF/BCKEY.DSA 中复制的重复文件

    我的代码构建得很好 但是当我尝试在调试中运行它时 出现以下错误 Error Execution failed for task app transformResourcesWithMergeJavaResForDebug com andro
  • 使用 START_STICKY 启动时服务进程被终止后的 onStartCommand

    我一直在阅读 Android 文档 我想知道是否有人可以阐明当以 START STICKY 启动的服务的进程被终止时服务实例会发生什么情况 我假设本地状态数据 实例变量 也丢失了 Android 在重新创建服务时是否会采取任何措施来帮助重新
  • 在 Android 中使用 AES 加密的最佳实践是什么?

    我为什么问这个问题 我知道人们对 AES 加密存在很多疑问 即使对于 Android 也是如此 如果您在网络上搜索 会发现很多代码片段 但在每个页面上 在每个 Stack Overflow 问题中 我都发现了另一个具有重大差异的实现 所以我
  • 如何从画布中删除路径区域(Android)

    我需要裁剪角落ImageView 不要将它们弄圆 而是擦除每个角上的三角形 似乎唯一的方法就是覆盖onDraw方法并使用从画布上删除这些区域Path 问题是我没有纯色背景 所以我需要擦除这些区域 但不要用某种颜色填充它们 我为此使用以下代码
  • foo.setVisibility(View.GONE) 和parent.removeView(foo) 之间的区别

    如果 foo 是一个视图 那么有什么区别foo setVisibility View GONE and fooParent removeView foo 我对两个语句之前和之后视图的内存消耗特别感兴趣 可见性设置为 GONE 的视图是否会消
  • 如何获取Android中的所有主屏幕?

    我是安卓开发新手 我知道每个主屏幕都是启动器中的一个工作区 我想获取屏幕上所有应用程序图标的所有位置信息 那么有没有办法获取这些屏幕对象及其图标信息的列表 ADD 我更期待的是应用程序图标和屏幕之间的关系 例如 我想要某个应用程序图标的位置
  • JavaScript 点击事件在 Android 4.0.4 默认浏览器上的 Samsung Galaxy SIII 上不起作用

    我在 Android 4 0 4 上使用 Samsung Galaxy SIII 的默认浏览器时遇到了最奇怪的问题 对于以下页面 单击链接将不会触发 JavaScript 处理程序 从其中一个 div 的内容中删除单个 a 字母使它们再次工
  • Android SDK WebView调用Activity

    我试图在单击 WebView 组件内的链接时启动活动 我的Webview已加载到里面Main java我想启动SubActivity java当点击网站内的链接时Main java 另外 如何将参数传递给此活动 Example inspec
  • 如何以编程方式检测android中可用的底部软导航栏?

    我试图通过 android 程序确定软导航栏 我没有找到直接的方法来确定 有没有办法找到导航栏的可用性 软导航栏图像在这里 以下方法对我有用并在许多设备上进行了测试 public boolean hasNavBar Resources re
  • android.view.WindowLeaked - 使用对话框和新意图时

    我已经尝试了 stackoverflow 上提供的所有可能的解决方案 但我仍然在 logcat 中遇到此错误 活动 com xyz MainActivity 泄露了最初在此处添加的窗口 com android internal policy

随机推荐

  • 数值分析与matlab学习笔记——多项式插值法

    文章目录 多项式插值 一点背景 多项式插值的存在唯一性 Lagrange插值法 n次插值基函数 拉格朗日插值函数 matlab代码及效果 Newton插值 均差 差商 均差的三种理解 N 基函数 牛顿插值函数 matlab代码及效果 误差分
  • openGL之API学习(一零六)wglGetProcAddress

    获取当前显卡中OpenGL函数的指针地址 PROC wglGetProcAddress LPCSTR Arg1 Arg1 Points to a null terminated string that is the name of the
  • 学习Linux命令的正确姿势

    大家好 我是良许 大家应该注意到了 最近我的公众号文章末尾都挂着自己录制的 Linux命令从小白到大神 课程 这个课程我从开始录制到制作完成 足足花了一个半月 如果加上前期的资料收集与教案准备 肯定有将近三个月 首先跟大家讲讲我为什么要开发
  • 电器元件——LM7805

    LM7805是一款常用的线性三端稳压IC 其外形封装虽然有多种 但输出电压皆为5V 区别就是封装不同 最大输出电流可能不一样 最常用的是如下图所示的TO 220封装的7805 TO 220封装的7805 上图所示的这种封装的7805 最高输
  • 设计模式 - Provider Pattern(提供者模式)

    设计模式 Provider Pattern 提供者模式 作者 webabcd 介绍 为一个API进行定义和实现的分离 示例 有一个Message实体类 对它的操作有Insert 和Get 方法 持久化数据在SqlServer数据库中或Xml
  • tcpreplay-tcprewrite

    1 介绍 参考链接 https www cnblogs com zlslch p 7325599 html utm source itdadao utm medium referral tcpreplay是一种pcap包的重放工具 它可以将
  • 【OpenCV】形态学图像处理学习笔记

    目录 腐蚀操作 膨胀操作 开运算操作 闭运算操作 梯度运算操作 礼帽运算操作 黑帽运算操作 腐蚀操作 cv2 erode 图像对象 内核 卷积核 interations 内核 核越大 腐蚀程度越高可自行定义 例如 kernel np one
  • Java面试题--shiro

    Shiro可以做哪些工作 Shiro可以帮助我们完成 认证 授权 加密 会话管理 与Web集成 缓存等 shiro有哪些组件 Authentication 身份认证 登录 验证用户是不是拥有相应的身份 Authorization 授权 即权
  • PG数据库恢复指定错误备份文件时怎么解决

    项目场景 测试环境中对分库分表PG库的同步数据 表结构等操作 问题描述 当我们在给分库分表执行备份恢复时 把不是本分片库的备份文件导入至本分片库 导致数据错乱 比如我们将一个8分库 0 7 的备份文件命名为dump 0 ddl dump 1
  • Sqli-labs之Less-20和Less-21和Less-22

    Less 20 基于错误的cookie头部POST注入 首先从已知的条件中我们知道这又是一道 头部注入 那么我们先输入正确的用户名和密码看一下登录成功是什么样子的 回显有User Agent IP这样从当次Request直接获取的 也有Co
  • 兴业银行利用以太坊区块链发行债券,金融科技冲击下的银行业未来(上篇)

    点击上方 蓝色字 可关注我们 暴走时评 日前 兴业银行通过以太坊区块链发行了类证券代币的债券 兴业银行的举动可能意味着银行承认 即使比特币或以太等无许可协议可能会带来颠覆性的威胁 他们依旧无法放弃其中潜在的巨大机遇 作者 Michael J
  • PHP+Laravel框架RabbitMQ简单使用

    RabbitMQ安装教程请转到 RabbitMQ安装教程 超详细 1 创建生产者 在app Http Controllers里创建一个php控制器文件 namespace App Http Controllers use App Http
  • docker中安装jupyter,并远程打开jupyter

    一 拉取镜像 拉取一个自带miniconda的镜像源 docker pull continuumio miniconda3 二 启动容器 docker run id p 宿主机端口 容器端口 name 自己取的容器名 v 宿主机目录 容器目
  • Python 综合应用小项目一

    数据库报错重连机制 利用异常捕获来获取mysql断开的报错 然后再重连 1 import MySQLdb as mysql 2 3 class DB 4 def init self host user passwd db name 5 se
  • 基于spring validation多层对象校验

    1 第一层对象定义 package com ybw validation demo vo import lombok AllArgsConstructor import lombok Data import lombok NoArgsCon
  • idea workspace.xml 报错

    1 找到 workspace xml 位置并删除 2 重新install
  • LeGO-LOAM 系列(1): LeGO-LOAM 安装以及概述

    一 github GitHub RobustFieldAutonomyLab LeGO LOAM 二 安装依赖 1 ROS Ubuntu 64 bit 16 04 ROS Kinetic 比较常规 就不赘述了 2 gtsam Georgia
  • 集合引用类型 上

    目录 Object Array 创建数组 数组的静态方法 数组空位 数组索引 检测数组 迭代器方法 复制和填充方法 转换方法 栈方法 队列方法 排序方法 操作方法 搜索和位置方法 迭代方法 归并方法 Object 显式地创建Object 的
  • Windows7 Python3 搭建Scrapy 爬虫框架

    Windows7 64位 Python3 7 安装Scrapy 提示如下错误信息 解决办法 1 在python库中下载twisted相应的包 whl文件 官网地址 https www lfd uci edu gohlke pythonlib
  • Android底部导航栏的三种风格实现

    一 效果图展示 如果动图没有动的话 也可以看下面这个静态图 以下挨个分析每个的实现 这里只做简单的效果展示 大家可以基于目前代码做二次开发 二 BottomNavigationView 这是 Google 给我们提供的一个专门用于底部导航的