1. 程式人生 > >iOS開發之自定義TabBarController-present(模態)出控制器

iOS開發之自定義TabBarController-present(模態)出控制器

點選TabBar present出控制器.gif

如上圖這種點選TabBar中間Button時present(模態)出控制器,而點選TabBar其它的Button則是蘋果預設的直接切換檢視的方式,現在很多APP都在使用,特別是直播APP,基本都把直播端模組放在這,最近在仿喵播時正好做到這,就想在網上找現成的框架,結果一直沒找到能滿足這種需求的框架,就自己動手寫了一個,沒有仔細打磨算不上框架,但絕對簡單好用!

自定義TabBarController實現原理很簡單,無非是用自定義的Button替換掉蘋果自帶的TabBar上的Button,一般目的是想TabBar上方顯示按鈕圖片,下面是文字;也就是每個Button下面有一個Label

。實現這些的重點是計算ButtonLabel的寬度和X座標值。

1、 新建三個類:

  • JFTabBar繼承自UIview
  • JFTabBarButton繼承自UIButton
  • JFTabBarController繼承自UITabBarController

2、具體程式碼:

  • JFTabBar.h
#import <UIKit/UIKit.h>

@class JFTabBar;

@protocol JFTabBarDelegate <NSObject>

@optional

- (void)tabBar:(JFTabBar *)tabBar didSelectedButtonFrom:(int
)from to:(int)to; @end @interface JFTabBar : UIView - (void)addTabBarButtonWithItem:(UITabBarItem *)item; - (void)customTheMiddleButtonWithImageName:(NSString *)imageName; @property (nonatomic, weak) id<JFTabBarDelegate> delegate; @end
  • JFTabBar.m
#import "JFTabBar.h"

#import "JFTabBarButton.h"
//中間按鈕被點選的通知 //此通知需要在JFTabBarController中監聽 static NSString * const JFTabBarClickMiddleButtonDidNotification = @"JFTabBarClickMiddleButtonDidNotification"; @interface JFTabBar(){ CGFloat _buttonW; } @property (nonatomic, weak) JFTabBarButton *selectedButton; @property (nonatomic, strong) UIButton *middleButton; @end @implementation JFTabBar - (void)addTabBarButtonWithItem:(UITabBarItem *)item { JFTabBarButton *button = [[JFTabBarButton alloc] init]; [self addSubview:button]; button.item = item; [button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchDown]; if (self.subviews.count == 1) { [self buttonClick:button]; } } - (void)buttonClick:(JFTabBarButton *)button { if ([self.delegate respondsToSelector:@selector(tabBar:didSelectedButtonFrom:to:)]) { [self.delegate tabBar:self didSelectedButtonFrom:(int)self.selectedButton.tag to:(int)button.tag]; } self.selectedButton.selected = NO; button.selected = YES; self.selectedButton = button; } /** * self.subviews.count + 1 這裡加1是將button的width按三個button計算,實際上是兩個button(如果不想present就不需要加1,下面兩個if判斷也可以去掉) * 兩個if判斷:1、是將button的x座標按三個button計算;2、tag值迴歸正常,不然無法正常切換控制器 * 如你需要新增更多的控制器,這裡就需要你自己計算,然後修改以上兩點 */ - (void)layoutSubviews { [super layoutSubviews]; CGFloat buttonH = self.frame.size.height; _buttonW = self.frame.size.width / (self.subviews.count + 1); CGFloat buttonY = 0; for (int index = 0; index < self.subviews.count; index++) { JFTabBarButton *button = self.subviews[index]; if (index == 1) index ++; CGFloat buttonX = index * _buttonW; button.frame = CGRectMake(buttonX, buttonY, _buttonW, buttonH); if (index == 2) index --; button.tag = index; } [self customTheMiddleButtonWithImageName:@"toolbar_live"]; } //自定義中間button按鈕 - (void)customTheMiddleButtonWithImageName:(NSString *)imageName { // 將Button居中 CGFloat middleButtonX = self.center.x - _buttonW / 2; _middleButton = [[UIButton alloc] initWithFrame:CGRectMake(middleButtonX, 0, _buttonW, self.frame.size.height)]; [_middleButton setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal]; [_middleButton addTarget:self action:@selector(didClickedMiddleButton:) forControlEvents:UIControlEventTouchDown]; [self addSubview:_middleButton]; } - (void)didClickedMiddleButton:(UIButton *)sender { //註冊中間button被點選通知 [[NSNotificationCenter defaultCenter] postNotificationName:JFTabBarClickMiddleButtonDidNotification object:self]; } @end
  • JFTabBarButton.h
#import <UIKit/UIKit.h>

@interface JFTabBarButton : UIButton

@property (nonatomic, strong) UITabBarItem *item;

@end
  • JFTabBarButton.m
static const double JFTabBarButtonImageRatio = 0.8;
#import "JFTabBarButton.h"

@implementation JFTabBarButton

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.imageView.contentMode = UIViewContentModeCenter;
        self.titleLabel.textAlignment = NSTextAlignmentCenter;
        self.titleLabel.font = [UIFont systemFontOfSize:11];
        [self setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
    }
    return self;
}

- (void)setHighlighted:(BOOL)highlighted {}

- (CGRect)imageRectForContentRect:(CGRect)contentRect{
    CGFloat imageW = contentRect.size.width;
    CGFloat imageH = contentRect.size.height * JFTabBarButtonImageRatio;
    return CGRectMake(0, 10, imageW, imageH);
}

//Button下需要文字時開啟
//- (CGRect)titleRectForContentRect:(CGRect)contentRect {
//    CGFloat titleY = contentRect.size.height * JFTabBarButtonImageRatio;
//    CGFloat titleW = contentRect.size.width;
//    CGFloat titleH = contentRect.size.height - titleY;
//    return CGRectMake(0, titleY, titleW, titleH);
//}

- (void)setItem:(UITabBarItem *)item {
    _item = item;
    //Button下需要文字時開啟
//    [item addObserver:self forKeyPath:@"title" options:0 context:nil];
    [item addObserver:self forKeyPath:@"image" options:0 context:nil];
    [item addObserver:self forKeyPath:@"selectedImage" options:0 context:nil];

    [self observeValueForKeyPath:nil ofObject:nil change:nil context:nil];
}

- (void)dealloc {
    //Button下需要文字時開啟
//    [self.item removeObserver:self forKeyPath:@"title"];
    [self.item removeObserver:self forKeyPath:@"image"];
    [self.item removeObserver:self forKeyPath:@"selectedImage"];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
//    [self setTitle:self.item.title forState:UIControlStateSelected];
//    [self setTitle:self.item.title forState:UIControlStateNormal];
    [self setImage:self.item.image forState:UIControlStateNormal];
    [self setImage:self.item.selectedImage forState:UIControlStateSelected];
}

@end
  • JFTabBarController.h

- (void)addAllChildViewControllers中新增除中間那個你需要present(模態)出的控制器

#import <UIKit/UIKit.h>

extern NSString * const JFTabBarClickMiddleButtonDidNotification;

@interface JFTabBarController : UITabBarController

@end
  • JFTabBarController.m
#import "JFTabBarController.h"

#import "JFTabBar.h"
#import "JFDisplayViewController.h"
#import "JFMeViewController.h"
#import "JFLiveViewController.h"

@interface JFTabBarController ()<JFTabBarDelegate>

@property (nonatomic, weak) JFTabBar *customTabBar;

@end

@implementation JFTabBarController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self customTabBarUI];
//  新增子控制器
    [self addAllChildViewControllers];

//  監聽中間按鈕點選事件
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(presentLiveController) name:@"JFTabBarClickMiddleButtonDidNotification" object:nil];
}
//  移除原生的TabBar
- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    for (UIView *childView in self.tabBar.subviews) {
        if ([childView isKindOfClass:[UIControl class]]) {
            [childView removeFromSuperview];
        }
    }
}

- (void)customTabBarUI {
    JFTabBar *customTabBar = [[JFTabBar alloc] init];
    customTabBar.frame = self.tabBar.bounds;
    customTabBar.delegate = self;
    [self.tabBar addSubview:customTabBar];
    self.customTabBar = customTabBar;
}

- (void)tabBar:(JFTabBar *)tabBar didSelectedButtonFrom:(int)from to:(int)to{
    self.selectedIndex = to;
}

//   下面換成你自己需要新增的控制器就好,只新增除中間需要present(模態)出的控制器。
- (void)addAllChildViewControllers {
    JFDisplayViewController *displayVC = [[JFDisplayViewController alloc] init];
    [self addChildViewController:displayVC title:@"視訊" imageName:@"toolbar_home" selectedImageName:@"toolbar_home_sel"];
    JFMeViewController *meVC = [[JFMeViewController alloc] init];
    [self addChildViewController:meVC title:@"個人" imageName:@"toolbar_me" selectedImageName:@"toolbar_me_sel"];
}

- (void)addChildViewController:(UIViewController *)childViewController title:(NSString *)title imageName:(NSString *)imageName selectedImageName:(NSString *)selectedImageName {
    childViewController.title = title;
    childViewController.tabBarItem.image = [UIImage imageNamed:imageName];
    childViewController.tabBarItem.selectedImage = [[UIImage imageNamed:selectedImageName] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:childViewController];
    [self addChildViewController:navigationController];
    [self.customTabBar addTabBarButtonWithItem:childViewController.tabBarItem];
}

//接收到點選中間按鈕的通知,present(模態)出控制器
- (void)presentLiveController {
    JFLiveViewController *jfLiveVC = [[JFLiveViewController alloc] init];
    [self presentViewController:jfLiveVC animated:YES completion:nil];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

//  移除通知
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end

說了這麼多,如果你也只是需要三個控制器,其實你只需要做這些:
1、下載JFTabBarController原始碼,解壓將JFTabBarController資料夾中檔案直接拖入你的xcode專案工程中。
2、在AppDelegate.m檔案中JFTabBarController設為window的根控制器。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.backgroundColor = [UIColor whiteColor];
    self.window.rootViewController = [[JFTabBarController alloc] init];
    [self.window makeKeyAndVisible];
    return YES;
}

3、重寫JFTabBarcontroller.m檔案中-(void)addAllChildViewControllers函式,新增子控制器
4、JFTabBarClickMiddleButtonDidNotification通知,
重寫JFTabBarcontroller.m檔案中- (void)presentLiveController方法。
你需要做的就這四步!