Implementation of bottom navigation bar of mainstream app based on uitabbarcontroller

Time:2020-6-29

preface

When there are multiple controllers in the app, you need to manage these controllers. Use one controller to manage multiple other controllers, as shown in the figure:

IOS uiview provides two special controllers, UINavigationController and uitabbarcontroller, to manage other controllers.

Here is a simple example to illustrate the basic usage:

Basic contents of UIWindow and uiviewcontroller

Create a new single view application project. In IOS applications, uiapplicationmain function is called in the main function of each program.

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

Let’s take a look at the prototype of uiapplicationmain function

UIKIT_EXTERN int UIApplicationMain(
  int argc, 
  char *argv[], 
  NSString * __nullable principalClassName, 
  NSString * __nullable delegateClassName
);

The previous argc and argv are parameters of the main function of ISO C standard, which are directly passed to uiapplicationmain for relevant processing. Principalclassname is the name of the application class, which must inherit from uiapplication class, and delegateclassname is the proxy class of the application class. If the main NIB file (in info.plist If it is specified in the file that the key is nsmainnibfile), the application object and the delegate connecting it will be found in the nib file object. This function will create uiapplication object according to principalclassname, then create a delegate object according to delegateclassname, and set the delegate attribute in uiapplication object as delegate object. Then, it will establish the main runloop of the application for event processing. First, callapplication:didFinishLaunchingWithOptions。 The program returns only when it exits normally (now IOS supports running in the background, and the system will forcibly kill the processes that are not used when necessary. Generally, this function terminates before the process returns).

//Startup program call completed
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //Create a window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    //Set the background color of the window
    self.window.backgroundColor = [UIColor whiteColor];
    
    //Set root controller
    ViewController *vc = [[ViewController alloc] init];
    self.window.rootViewController = vc;

    //Set up and display the main window
    [self.window makeKeyAndVisible];
    
    return YES;
}

UIWindow is a kind of special uiview, usually there is only one UIWindow in an application. After the IOS program is started, the first view control created is UIWindow, then a view of the controller is created, and finally the view of the controller is added to the UIWindow, so the view of the controller is displayed on the screen. The reason why an IOS program can be displayed on the screen is that it has UIWindow, that is to say, no UI interface can be seen without UIWindow.

Controller creation:

UIViewController *vc = [UIViewController alloc] init];

You can use the isviewloaded method to determine whether the view of a uiviewcontroller has been loaded; after the view of the controller is loaded, the viewdidload method will be called.

Add view to UIWindow:

  • Add the view directly to the UIWindow, regardless of the controller corresponding to the view.
- (void)addSubView:(UIView *)view;
  • By setting the root controller, the view of rootviewcontroller is automatically added to UIWindow to manage the lifecycle of rootviewcontroller.
@property(nonatomic,retain) UIViewController *rootViewController;

Get rootviewcontroller:

The first method:

UIWindow *window = [UIApplication sharedApplication].keyWindow;
UIViewController *rootViewController = window.rootViewController;

The second method:

AppDelegate *appdelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
UIViewController *rootViewController = appdelegate.window.rootViewController;

Basic contents of UINavigationController and uitabbarcontroller

UINavigationController saves the sub controller in the form of stack. A controller can be pushed into the stack by using push method, and the top controller can be removed by pop method.

How to open viewcontroller:

 - (void)pushViewController:(UIViewController*)viewController animated:(BOOL)animated;

There are three ways to remove the viewcontroller:

Remove the controller at the top of the stack
- (UIViewController*)popViewControllerAnimated:(BOOL)animated;
Return to the specified sub controller
- (NSArray*)popToViewController:(UIViewController*)viewController animated:(BOOL)animated;
Back to root controller (bottom of stack controller)
- (NSArray*)popToRootViewControllerAnimated:(BOOL)animated;

Initialize UINavigationController:

Method 1

UINavigationController *nv = [[UINavigationController alloc] init];  

Method 2

UINavigationController *nv = [[UINavigationController alloc] initWithRootViewController:rootViewController];

Uitabbarcontroller is similar to UINavigationController. Uitabbarcontroller can easily manage multiple controllers and switch between controllers. Typical examples are QQ, wechat, etc. However, the view managed by uitabbarcontroller always exists, and UINavigationController will be destroyed after pop to release memory. Uitabbarcontroller is usually used as the rootviewcontroller of the whole program and cannot be added to other container viewcontrollers.

Use steps of uittabbarcontroller:

  1. Initialize uittabbarcontroller
  2. Create a child controller
  3. Add child controller to uittabbarcontroller
  4. Set the rootviewcontroller of UIWindow to uitabbarcontroller

Add a sub controller to the uitabbarcontroller:

Method 1: add a single sub controller

- (void)addChildViewController:(UIViewController*)childController;

Method 2: add multiple sub controllers

view.viewControllers = NSArray *childController;

UINavigationController is nested in uitabbarcontroller

Uitabbarcontroller is nested in UINavigationController:

Project practice

Extract the logic of uitabbarcontroller into a separate viewcontroller. You can create a new viewcontroller that inherits from uitabbarcontroller.

AppDelegate.m:

//Startup program call completed
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    //Create a window
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    //Set the background color of the window
    self.window.backgroundColor = [UIColor whiteColor];
    
    //Set root controller
    ViewController *vc = [[ViewController alloc] init];
    self.window.rootViewController = vc;

    //Set up and display the main window
    [self.window makeKeyAndVisible];
    
    return YES;
}

ViewController.h:

@interface ViewController : UITabBarController

@end

ViewController.m:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //Create sub controller
    HomeViewController *homeVC=[[HomeViewController alloc] init];
    [self setTabBarItem:homeVC.tabBarItem
                  Title: @ "home page"
              titleSize:13.0
          titleFontName:@"HeiTi SC"
          selectedImage:@"i_tab_home_selected"
     selectedTitleColor:[UIColor redColor]
            normalImage:@"i_tab_home_normal"
       normalTitleColor:[UIColor grayColor]];
    
    BlogViewController *blogVC=[[BlogViewController alloc] init];
    [self setTabBarItem:blogVC.tabBarItem
                  Title: @ "blog"
              titleSize:13.0
          titleFontName:@"HeiTi SC"
          selectedImage:@"i_tab_blog_selected"
     selectedTitleColor:[UIColor redColor]
            normalImage:@"i_tab_blog_normal"
       normalTitleColor:[UIColor grayColor]];
    
    UINavigationController *homeNV = [[UINavigationController alloc] initWithRootViewController:homeVC];
    UINavigationController *blogNV = [[UINavigationController alloc] initWithRootViewController:blogVC];
    //Add sub controller to uitabbarcontroller
    self.viewControllers = @[homeNV, blogNV];
}

We usually need to set the tabbaritem. We can encapsulate a settabbaritem method. We only need to configure it simply.

- (void)setTabBarItem:(UITabBarItem *)tabbarItem
                title:(NSString *)title
            titleSize:(CGFloat)size
        titleFontName:(NSString *)fontName
        selectedImage:(NSString *)selectedImage
   selectedTitleColor:(UIColor *)selectColor
          normalImage:(NSString *)unselectedImage
     normalTitleColor:(UIColor *)unselectColor
{
    
    //Set up pictures
    tabbarItem = [tabbarItem initWithTitle:title image:[[UIImage imageNamed:unselectedImage]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] selectedImage:[[UIImage imageNamed:selectedImage]imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
    
    //S no font color selected
    [[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName:unselectColor,NSFontAttributeName:[UIFont fontWithName:fontName size:size]} forState:UIControlStateNormal];
    
    //Select font color
    [[UITabBarItem appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName:selectColor,NSFontAttributeName:[UIFont fontWithName:fontName size:size]} forState:UIControlStateSelected];
}

Then customize each subviewcontroller. For example, blogviewcontroller. H can write as follows:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIButton *helloBtn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, SCREEN_WIDTH - 200, 50)];
    helloBtn.backgroundColor = [UIColor redColor];
    [helloBtn setTitle:@"hello world" forState:UIControlStateNormal];
    [helloBtn addTarget:self action:@selector(showToast) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:helloBtn];
}

- (void)showToast{
    //Open new viewcontroller
    BlogDetailViewController *blogDetail = [[BlogDetailViewController alloc] init];
    blogDetail.hidesBottomBarWhenPushed=YES;
    [self.navigationController pushViewController:blogDetail animated:YES];
}

This article source code: https://github.com/zhaomenghu…

reference resources

Simple use of UINavigationController & uitabbarcontroller


I recently held a series of lectures on 5 + app in segmentfault. Welcome to watch:

  • Engineering practice of HTML5 + app development
  • Offline integration of 5 + SDK on Android platform developed by HTML5 + app