android 导航栏封装,Android底部导航栏的主界面实现

原标题:Android底部导航栏的主界面实现

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

528e08a1b423482344b9c825fbfef1aa.png

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

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

f11b0bca6d4ded0fe890b149828d7d2c.png

activity_main.xml

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

android:id="@+id/main_layout"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:layout_weight="1"/>

android:layout_width="match_parent"

android:layout_height="1px"

android:background="@color/colorPrimaryDark"

/>

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">

android: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="首页"

/>

android:layout_width="1px"

android:layout_height="match_parent"

android:background="@color/colorPrimaryDark"

/>

android: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="游戏"

/>

android:layout_width="1px"

android:layout_height="match_parent"

android:background="@color/colorPrimaryDark"

/>

android: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="视频"

/>

android:layout_width="1px"

android:layout_height="match_parent"

android:background="@color/colorPrimaryDark"

/>

android: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="我的"

/>

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

privateHomeFragment homeFragment;

privateGameFragment gameFragment;

privateVideoFragment videoFragment;

privateMineFragment mineFragment;

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

privatevoid 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,这里我们讲解后者的实现方式。

privatevoidinitFragment(){

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;

}

我们来逐行分析代码

首先开启一个事务

FragmentTransactiontransaction= 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

publicvoidonClick(View view){

switch(view.getId){

caseR.id.main_home:

switchContent(home);

break;

caseR.id.main_game:

switchContent(game);

break;

caseR.id.main_video:

switchContent(video);

break;

caseR.id.main_mine:

switchContent(mine);

break;

}

}

5.定位到switchContent方法

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

publicvoidswitchContent(View view){

Fragment fragment;

if(view== home){

if(homeFragment== null){

homeFragment= newHomeFragment;

}

fragment= homeFragment;

} elseif(view== game){

if(gameFragment== null){

gameFragment= newGameFragment;

}

fragment= gameFragment;

} elseif(view== video){

if(videoFragment== null){

videoFragment= newVideoFragment;

}

fragment= videoFragment;

} elseif(view== mine){

if(mineFragment== null){

mineFragment= newMineFragment;

}

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,一切正常。

0374bffb42b3156e8ab230381160b06f.png

接下来,点击第二个标签,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附上!

资源下载:https://download.csdn.net/download/u014078990/10676437

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

原文链接:https://blog.csdn.net/u014078990/article/details/82763155 返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值