在主流app中,应用的主界面都是底部含有多个标签的导航栏,点击可以切换到相应的界面,如图:

接下来将描述下其实现过程。

1.首先是分析界面,底部导航栏我们可以用一个占满屏幕宽度、包裹着数个标签TextView、方向为横向horizontal的线性布局LinearLayout。上方则是一个占满剩余空间的FrameLayout。

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"android:orientation="vertical"><FrameLayoutandroid:id="@+id/main_layout"android:layout_width="match_parent"android:layout_height="match_parent"android:layout_weight="1"/><Viewandroid:layout_width="match_parent"android:layout_height="1px"android:background="@color/colorPrimaryDark"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:id="@+id/main_home"android:layout_width="wrap_content"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:padding="20dp"android:text="首页"/><Viewandroid:layout_width="1px"android:layout_height="match_parent"android:background="@color/colorPrimaryDark"/><TextViewandroid:id="@+id/main_game"android:layout_width="wrap_content"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:padding="20dp"android:text="游戏"/><Viewandroid:layout_width="1px"android:layout_height="match_parent"android:background="@color/colorPrimaryDark"/><TextViewandroid:id="@+id/main_video"android:layout_width="wrap_content"android:layout_weight="1"android:layout_height="wrap_content"android:gravity="center"android:padding="20dp"android:text="视频"/><Viewandroid:layout_width="1px"android:layout_height="match_parent"android:background="@color/colorPrimaryDark"/><TextViewandroid:id="@+id/main_mine"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:padding="20dp"android:text="我的"/></LinearLayout>
</LinearLayout>

2.四个标签对应四个Fragment,我们新建四个Fragment,布局放个TextView用于区分即可。

private HomeFragment homeFragment;
private GameFragment gameFragment;
private VideoFragment videoFragment;
private MineFragment mineFragment;

3.打开MainActivity,首先初始化控件

private void initView() {home= findViewById(R.id.main_home);game= findViewById(R.id.main_game);video= findViewById(R.id.main_video);mine= findViewById(R.id.main_mine);layout= findViewById(R.id.main_layout);home.setOnClickListener(this);game.setOnClickListener(this);video.setOnClickListener(this);mine.setOnClickListener(this);
}

onClick点击事件放在后面处理

3.初始化四个fragment

我们初衷是让fragment加载一次后,重复点击或者切换回来都不会再加载以耗费资源,这里常见的处理方式有viewpager的懒加载和fragment的hide、show,这里我们讲解后者的实现方式。

private void initFragment() {FragmentTransaction transaction= getSupportFragmentManager().beginTransaction();if (homeFragment!= null&& homeFragment.isAdded()){transaction.remove(homeFragment);}if (gameFragment!= null&& gameFragment.isAdded()){transaction.remove(gameFragment);}if (videoFragment!= null&& videoFragment.isAdded()){transaction.remove(videoFragment);}if (mineFragment!= null&& mineFragment.isAdded()){transaction.remove(mineFragment);}transaction.commitAllowingStateLoss();homeFragment= null;gameFragment= null;videoFragment= null;mineFragment= null;home.performClick();
}

我们来逐行分析代码

首先开启一个事务

FragmentTransaction transaction= getSupportFragmentManager().beginTransaction();

进行Fragment的非空处理

if (homeFragment!= null&& homeFragment.isAdded()){transaction.remove(homeFragment);
}
if (gameFragment!= null&& gameFragment.isAdded()){transaction.remove(gameFragment);
}
if (videoFragment!= null&& videoFragment.isAdded()){transaction.remove(videoFragment);
}
if (mineFragment!= null&& mineFragment.isAdded()){transaction.remove(mineFragment);
}
transaction.commitAllowingStateLoss();

将所有fragment设为null,自动执行homefragment的点击事件,即默认显示HomeFragment

homeFragment= null;
gameFragment= null;
videoFragment= null;
mineFragment= null;
home.performClick();

4.回到四个底部标签的点击事件,我们执行自定义的switchContent方法,将当前点击标签的view作为参数传进去

@Override
public void onClick(View view) {switch (view.getId()){case R.id.main_home:switchContent(home);break;case R.id.main_game:switchContent(game);break;case R.id.main_video:switchContent(video);break;case R.id.main_mine:switchContent(mine);break;}
}

5.定位到switchContent方法

新建一个fragment对象,当点击某个标签时,如果当前fragment对象为空,就生成一个对应fragment的对象实例

public void switchContent(View view){Fragment fragment;if (view== home){if (homeFragment== null){homeFragment= new HomeFragment();}fragment= homeFragment;}else if (view== game){if (gameFragment== null){gameFragment= new GameFragment();}fragment= gameFragment;}else if (view== video){if (videoFragment== null){videoFragment= new VideoFragment();}fragment= videoFragment;}else if (view== mine){if (mineFragment== null){mineFragment= new MineFragment();}fragment= mineFragment;}else {return;}

生成对象后,我们就可以进行fragment的添加显示工作了。

FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (mContent == null) {transaction.add(layout.getId(), fragment).commit();mContent = fragment;
}
if (mContent != fragment) {if (!fragment.isAdded()) {transaction.hide(mContent).add(layout.getId(), fragment).commitAllowingStateLoss();} else {transaction.hide(mContent).show(fragment).commitAllowingStateLoss();}mContent = fragment;
}
home.setSelected(false);
home.setSelected(false);
home.setSelected(false);
home.setSelected(false);
view.setSelected(true);

分析这段代码,我们主要是用当前碎片mContent和上个碎片fragment做比较,这样用来判断底部导航栏是否点击进行了切换,首先当应用打开时,因为我们前面调用了第一个标签自动点击方法。

home.performClick();

看流程,因为此时mContent还为null,所以走这段代码

if (mContent == null) {transaction.add(layout.getId(), fragment).commit();mContent = fragment;
}

此时fragment即为HomeFragment对象,页面将显示HomeFragment,并将该对象赋给mContent。

此时HomeFragment生命周期如下,从Attach()走到onResume(),一切正常。

接下来,点击第二个标签,fragment为gameFragment,mContent为homeFragment。两者不等,走这段方法。

if (mContent != fragment) {if (!fragment.isAdded()) {transaction.hide(mContent).add(layout.getId(), fragment).commitAllowingStateLoss();} else {transaction.hide(mContent).show(fragment).commitAllowingStateLoss();}mContent = fragment;
}

分析代码,GameFragment因为还没被加载过,所以先走

transaction.hide(mContent).add(layout.getId(), fragment).commitAllowingStateLoss();

即隐藏掉mContent即HomeFragment,在将GameFragment加载显示出来。

这时看GameFragment的生命周期,一切正常。

这时我们再点击回HomeFragment,此时fragment为HomeFragment,mContent为GameFragment,同时HomeFragment因为被add过,所以走

transaction.hide(mContent).show(fragment).commitAllowingStateLoss();

这条语句指隐藏fragment同时不必加载add已经加载过的fragment,直接show就可以,commitAllowingStateLoss方法与commit方法作用类似,更适用这种频繁切换页面下的提交工作,避免crash。

同时打开日志,发现HomeFragment并没有被销毁重载,这样就达到了我们不想切换频繁加载的目的。

至此全部完成,Demo附上!
资源下载

Android开发丶底部导航栏相关推荐

  1. android 开发实例 底部导航栏(1)

    1.使用LinearLayout 底部布局+imageView 实现 底部四个主导航页面 布局文件  activity_main.xml <LinearLayout xmlns:android= ...

  2. Android开发之底部导航栏标准

    以下是封装的库源码: 1 package com.example.oldtab; 2 3 import java.util.ArrayList; 4 5 import android.content. ...

  3. android仿微信的activity平滑水平切换动画,Android实现简单底部导航栏 Android仿微信滑动切换效果...

    Android实现简单底部导航栏 Android仿微信滑动切换效果 发布时间:2020-10-09 19:48:00 来源:脚本之家 阅读:96 作者:丶白泽 Android仿微信滑动切换最终实现效果 ...

  4. 微信小程序开发错误——底部导航栏没有显示完全

    微信小程序开发错误--底部导航栏没有显示完全 原因:由于在app.json中设置跳转页面时,假设有A.B.C.D四个图标(点击可以跳转),B和C的跳转页面相同,C的图标就会覆盖B的图标,B的图标就相当 ...

  5. android仿咸鱼底部导航栏,Flutter沉浸式状态栏/AppBar导航栏/仿咸鱼底部凸起导航栏效果...

    如下图:状态栏是指android手机顶部显示手机状态信息的位置. android 自4.4开始新加入透明状态栏功能,状态栏可以自定义颜色背景,使titlebar能够和状态栏融为一体,增加沉浸感. 如上 ...

  6. JFTabBar android强大的底部导航栏框架 (微信底部导航栏效果)

    TabBar这个名字相信很多学过一点IOS程序员都知道它是用来干嘛的,但本人也并非擅长开发IOS程序员,只是略懂略懂....这是一个很强大的TabBar,可满足很多需求.用起来也非常简单,在oncre ...

  7. php仿微信底部菜单,Android实现简单底部导航栏 Android仿微信滑动切换效果

    Android仿微信滑动切换最终实现效果: 大体思路: 1. 主要使用两个自定义View配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标; 2. 底部导航栏 ...

  8. 开发vue底部导航栏组件

    这个想法源于最近自己在开发一个移动端博客的一个底部导航栏,原型设计如下: 我们来分析一下这个导航栏,其实很简单啦,就是自适应固定在底部 我们可以使用CSS3属性display:flex设置父级盒子为伸 ...

  9. android滑动菜单图标,Android实现简单底部导航栏 Android仿微信滑动切换效果

    Android仿微信滑动切换最终实现效果: 大体思路: 1. 主要使用两个自定义View配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标; 2. 底部导航栏 ...

  10. android 底部滑动效果怎么做,Android实现简单底部导航栏 Android仿微信滑动切换效果...

    android仿微信滑动切换最终实现效果: 大体思路: 1. 主要使用两个自定义view配合实现; 底部图标加文字为一个自定义view,底部导航栏为一个载体,根据需要来添加底部图标; 2. 底部导航栏 ...

最新文章

  1. Go 1.16 的这个新变化需要适应下:go get 和 go install 的变化
  2. 使用树形结构保存实体
  3. MySQL分布式事务(XA事务)
  4. matlab_矩阵的灵活操作
  5. (三) LtRecyclerView v2.x (自定义上拉和下拉刷新View)
  6. 【学习Python】的网站
  7. 基于数据处理的CSV格式行列变换及数据清洗
  8. Linux命令 - watch
  9. Redis集群搭建笔记
  10. python的数据库应用,Python数据库应用
  11. ajax post 与get方法 data写法
  12. 太强大了 | 一键生成,太强大了……
  13. 程序员的自我修养——读《软技能-代码之外的生存指南》笔记
  14. WinForm数据绑定--BindingContext
  15. 360浏览器在b站看直播html5,用360浏览器看Bilibili视频很卡怎么办_360浏览器看B站视频卡如何解决-win7之家...
  16. c语言智能小车项目的感想,智能小车实训报告
  17. 最短路径系列【最短路径、哈密顿路等】
  18. 统计原理笔记 Notes for Statistics I
  19. 解决AndroidStudio中使用.9图片不生效的问题
  20. A003-182-2268-黄清梅

热门文章

  1. mp4转mp3,mp4转换成mp3方法步骤
  2. c语言混合运算优先级判断,《C语言解惑》—— 3.1 混合运算要小心
  3. 基于python/scipy学习概率统计(2):伯努利分布(Bernoulli Distribution)
  4. CATIA二次开发——元素隐藏
  5. android远程协助
  6. 【出国面试】出国 交换 / 访学 / 留学 国外导师面试经验分享
  7. excel如何把多张表合并成一个表_如何将多个 Excel 工作簿的工作表合并成一个工作表?...
  8. leetcode寻找重复数
  9. 最新!!2018南京买房政策大全
  10. 【Python】使用分隔符拆分字符串