天天看点

客户端开发之 实现底层菜单栏

目前市面上主流的app 都会采用多页面管理,以承载更多的内容,这里会简单叙述 通过底部按钮 是血页面的切换。

android 篇:

android   通过fragment 有三种实现方式:

整体大同小异,菜鸟教程有详细讲述: https://www.runoob.com/w3cnote/android-tutorial-fragment-demo1.html

或者可以使用第三方库:

/**Bottom Navigation**/
    implementation 'com.ashokvarma.android:bottom-navigation-bar:2.2.0'
           
<com.ashokvarma.bottomnavigation.BottomNavigationBar
        android:id="@+id/bottom_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        app:bnbActiveColor="@color/color_ffffff"
        app:bnbInactiveColor="@color/color_929292"
        app:bnbBackgroundColor="@color/colorPrimaryDark"/>
           

Java:

BottomNavigationBar bottomBar;

   @Override
   protected void initialize() {
        setTopTitle(getResources().getString(R.string.t_home), true);
        setLeftBtn(false, 0, null);

        bottomBar.setTabSelectedListener(this);
        bottomBar.setMode(BottomNavigationBar.MODE_FIXED);
        bottomBar.setBackgroundStyle(BottomNavigationBar.BACKGROUND_STYLE_RIPPLE);
        bottomBar.addItem(new BottomNavigationItem(ContextCompat.getDrawable(this, R.mipmap.icon_home_press),
                getString(R.string.t_home)).setInactiveIcon(ContextCompat.getDrawable(this, R.mipmap.icon_home)))
                .addItem(new BottomNavigationItem(ContextCompat.getDrawable(this, R.mipmap.icon_discover_press),
                        getString(R.string.t_serive)).setInactiveIcon(ContextCompat.getDrawable(this, R.mipmap.icon_discover)))
                .addItem(new BottomNavigationItem(ContextCompat.getDrawable(this, R.mipmap.icon_hot_press),
                        getString(R.string.t_learn)).setInactiveIcon(ContextCompat.getDrawable(this, R.mipmap.icon_hot)))
                .addItem(new BottomNavigationItem(ContextCompat.getDrawable(this, R.mipmap.icon_user_press),
                        getString(R.string.t_person)).setInactiveIcon(ContextCompat.getDrawable(this, R.mipmap.icon_user)))
                .setFirstSelectedPosition(0)
                .initialise();
        setDefaultFragment();
    }

    //点击事件处理
    @Override
    public void onTabSelected(int position) {}
           

 fragment 处理逻辑一致,选择一种自己喜欢的方式。

第三方控件相对于 可以让开发者少些布局,将底部按钮进行封装 ,点击具有动画效果,整体对比,减少开发工作量 。

客户端开发之 实现底层菜单栏

旧版仅供参考 :布局如下:

<FrameLayout
        android:id="@+id/ly_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_above="@+id/rg_tab_bar"></FrameLayout>

    <RadioGroup
        android:id="@+id/rg_tab_bar"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:layout_alignParentBottom="true"
        android:background="@color/white"
        android:orientation="horizontal">

        <RadioButton
            android:id="@+id/rb_Home"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_infromation"
            android:text="首页"/>

        <RadioButton
            android:id="@+id/rb_Service"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_health"
            android:text="服务"/>

        <RadioButton
            android:id="@+id/rb_Preson"
            style="@style/tab_menu_item"
            android:drawableTop="@drawable/tab_menu_home"
            android:text="我"/>


    </RadioGroup>

   
           

创建3个fragment 和RadioButton  相对应 ly_content 内容匹配 这里有个易错点 就是 

import android.app.Fragment; 与

import android.support.v7.app.Fragment;  这个传递参数  继承 Fragment 两个内容要匹配

这里一定要注意  一不小心就容易出错。 实际上 同样 不同情况 也容易出错

private void init() {
        rg_tab_bar = (RadioGroup) findViewById(R.id.rg_tab_bar);
        fManager = getFragmentManager();
        rg_tab_bar.setOnCheckedChangeListener(this);
        rb_home=(RadioButton)findViewById(R.id.rb_Home);
        rb_home.setChecked(true);
    }
           
@Override
    public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
        FragmentTransaction fragmentTransaction=fManager.beginTransaction();
        hideAllFragment(fragmentTransaction);
        switch (checkedId){
            case R.id.rb_Home:
                if (fg1==null){
                fg1=new HomeFragment();
                fragmentTransaction.add(R.id.ly_content,fg1);
                }else {
                    fragmentTransaction.show(fg1);
                }
                break;
            case R.id.rb_Service:
                if (fg2==null){
                    fg2=new ServiceFragment();
                    fragmentTransaction.add(R.id.ly_content,fg2);
                }else {
                    fragmentTransaction.show(fg2);
                }
                break;
            case R.id.rb_Preson:
                if (fg3==null){
                    fg3=new PresonFragment();
                    fragmentTransaction.add(R.id.ly_content,fg3);
                }else {
                    fragmentTransaction.show(fg3);
                }
                break;
        }
        fragmentTransaction.commit();
    }

    //隐藏所有Fragment
    private void hideAllFragment(FragmentTransaction fragmentTransaction) {
        if (fg1 != null) fragmentTransaction.hide(fg1);
        if (fg2 != null) fragmentTransaction.hide(fg2);
        if (fg3 != null) fragmentTransaction.hide(fg3);
    }
           
客户端开发之 实现底层菜单栏

IOS篇:

相对于 android 使用碎片化的fragment 实现 底部菜单栏 而 IOS端 主要是通过 结合视图和控制器构建tabbar 样式页面。

客户端开发之 实现底层菜单栏

UITabBarController

UITabBarController 功能就是管理理多个 UIViewController 切换 通过点击底部对应按钮,选中对应需要展示的 UIViewController

UITabBar 

  • 按照加⼊入 UITabbarController 的顺序展示
  • 展示的内容有对应 UIViewController 设置
  • 系统负责点击的响应和切换

相对于 Android 和 iOS 之间的切换,都是面向对象的语言。主要语法上的差异,对比刚开始学习fragment 的同学,可能对碎片这个使用的理解不太清楚,而iOS这里就是比较好理解了,简单明了,代码如下:

iOS13里生命周期有所调整需要将代码移动到SceneDelegate.m中

iOS13中appdelegate的职责发现了改变:

iOS13之前,Appdelegate的职责全权处理App生命周期和UI生命周期;

iOS13之后,Appdelegate的职责是:

1、处理 App 生命周期

2、新的 Scene Session 生命周期

那UI的生命周期交给新增的Scene Delegate处理

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene];
    
    UITabBarController *tabbarController = [[UITabBarController alloc] init];
    HomeViewController *homeViewController = [[HomeViewController alloc] init];
    homeViewController.view.backgroundColor = [UIColor whiteColor];
    FindViewController *findViewController = [[FindViewController alloc] init];
    ChatViewController *chatViewController = [[ChatViewController alloc] init];
    PersonalViewController *personalViewController = [[PersonalViewController alloc] init];
    [tabbarController setViewControllers:@[homeViewController, findViewController, chatViewController, personalViewController]];
    
    self.window.rootViewController = tabbarController;
    [self.window makeKeyAndVisible];
    [self.window makeKeyWindow];
}
           
@implementation HomeViewController

- (instancetype)init
{
    self = [super init];
    if (self) {
        self.tabBarItem.title = @"首页";
        self.tabBarItem.image = [UIImage imageNamed:@"icon.bundle/[email protected]"];
        self.tabBarItem.selectedImage = [UIImage imageNamed:@"[email protected]"];
    }
    return self;
}
           

其他viewController 同理,也可以在外部直接调用设置,最好改viewController的设置写在内部。