天天看點

UITabBarController的使用自定義UITabBar樣式

UITabBarController的使用過程中,可能會出現需要自定義UITabBar樣式的時候,下面介紹兩種實作方法。

方法1

存在N個視圖控制器,且需要使用自定義的UITabBar樣式來進行互動操作哪個視圖控制器的顯示。具體做法是在UITabBarController中的view中添加自定義樣式的子視圖,設定子視圖響應方法跳轉對應的視圖控制器,然後再通過UITabBarController的代理方法重置自定義樣式的子視圖狀态。

代碼示例,繼承UITabBarController的方式實作

#import "BaseTabBarController.h"
#import "MainVC.h"
#import "MineVC.h"
#import "AddVC.h"

@interface BaseTabBarController () <UITabBarControllerDelegate>

@property (nonatomic, strong) UIButton *addButton;

@end

@implementation BaseTabBarController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    [self initlizeAddButton];
}

#pragma mark - 實作

- (void)initlizeAddButton
{
    self.delegate = self;
    [self addChildVc:[[MainVC alloc] init] title:@"首頁" image:@"homeNormal" selectedImage:@"homeSelected"];
    [self addChildVc:[[AddVC alloc] init] title:nil image:nil selectedImage:nil];
    [self addChildVc:[[MineVC alloc] init] title:@"我的" image:@"mineNormal" selectedImage:@"mineSelected"];

    self.tabBar.backgroundColor = [UIColor yellowColor];
    
    self.addButton = [[UIButton alloc] initWithFrame:CGRectMake((self.tabBar.frame.size.width - 70.0) / 2, (self.view.frame.size.height - 70.0) - 44.0, 70.0, 70.0)];
    self.addButton.backgroundColor = [UIColor yellowColor];
    self.addButton.layer.cornerRadius = 35;
    self.addButton.layer.masksToBounds = YES;
    [self.addButton setImage:[UIImage imageNamed:@"addNormal"] forState:UIControlStateNormal];
    [self.addButton setImage:[UIImage imageNamed:@"addSelected"] forState:UIControlStateSelected];
    [self.addButton addTarget:self action:@selector(addClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.addButton];
    [self.view bringSubviewToFront:self.addButton];
}

- (void)addClick:(UIButton *)button
{
    button.selected = YES;
    button.userInteractionEnabled = NO;
    self.selectedIndex = 1;
}

- (void)addChildVc:(UIViewController *)childVc title:(NSString *)title image:(NSString *)image selectedImage:(NSString *)selectedImage
{
    // 設定子控制器的文字(可以設定tabBar和navigationBar的文字)
    if (title) {
        childVc.title = title;
    }
    
    // 設定子控制器的tabBarItem圖檔
    if (image) {
        childVc.tabBarItem.image = [UIImage imageNamed:image];
    }
    
    // 禁用圖檔渲染
    if (selectedImage) {
        childVc.tabBarItem.selectedImage = [[UIImage imageNamed:selectedImage] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    }
    
    // 設定文字的樣式
    [childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]} forState:UIControlStateNormal];
    [childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor redColor]} forState:UIControlStateSelected];
    // 為子控制器包裝導航控制器
    UINavigationController *navigationVc = [[UINavigationController alloc] initWithRootViewController:childVc];
    // 添加子控制器
    [self addChildViewController:navigationVc];
}

#pragma mark - delegate

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
    // 方法2 時
    if (self.addButton) {
        self.addButton.selected = NO;
        self.addButton.userInteractionEnabled = YES;
    }
    return YES;
}

@end
           

效果圖

UITabBarController的使用自定義UITabBar樣式

方法2

存在N個視圖控制器,且需要使用自定義的UITabBar樣式來進行互動操作其他,N為偶數;如有兩個視圖控制器,然後自定義的樣式控制其他視圖。具體做法繼承

UITabBar

,并在UITabBarController中設定。

代碼示例,繼承UITabBarController的方式實作

#import <UIKit/UIKit.h>

@protocol AddItemTabBarDelegate <NSObject>

- (void)tabBarItemClick:(UIButton *)button;

@end

@interface AddItemTabBar : UITabBar

@property (nonatomic, weak) id<AddItemTabBarDelegate>delegate;

@property (nonatomic, strong) UIButton *button;
@property (nonatomic, strong) UILabel *label;

/// 根據實際的視圖數組數設定(如:實際的UITabBarController的viewControllers數量為2,則為2)
@property (nonatomic, assign) NSInteger number;

@end

#import "AddItemTabBar.h"

@interface AddItemTabBar ()

@end

@implementation AddItemTabBar

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.translucent = NO;
        //
        self.button = [UIButton buttonWithType:UIButtonTypeCustom];
        self.button.backgroundColor = [UIColor greenColor];
        self.button.layer.masksToBounds = YES;
        [self.button setImage:[UIImage imageNamed:@"addNormal"] forState:UIControlStateNormal];
        [self.button setImage:[UIImage imageNamed:@"addSelected"] forState:UIControlStateSelected];
        [self.button addTarget:self action:@selector(plusBtnDidClick) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:self.button];
        //
        self.label = [[UILabel alloc] init];
        self.label.font = [UIFont systemFontOfSize:10];
        self.label.textColor = [UIColor blackColor];
        self.label.textAlignment = NSTextAlignmentCenter;
        [self addSubview:self.label];
    }
    return self;
}

- (void)plusBtnDidClick
{
    if (self.delegate && [self.delegate respondsToSelector:@selector(tabBarItemClick:)]) {
        [self.delegate tabBarItemClick:self.button];
    }
}

// 調整子視圖的布局
- (void)layoutSubviews
{
    [super layoutSubviews];
    CGFloat width = self.frame.size.width / (self.number + 1);
    Class class = NSClassFromString(@"UITabBarButton");
    for (UIView *view in self.subviews) {
        if ([view isEqual:self.label]) {
            // self.label
            view.frame = CGRectMake(0, 0, width, 15);
            view.center = CGPointMake(self.frame.size.width / self.number, self.frame.size.height - view.frame.size.height + 8);
        } else if ([view isEqual:self.button]) {
            // self.button
            CGSize size = CGSizeMake(width, self.frame.size.height);
            size = CGSizeMake(80.0, 80.0);
            view.layer.cornerRadius = size.width / 2;
            view.frame = CGRectMake(0, 0, size.width, size.height);
//            [view sizeToFit];
            view.center = CGPointMake(self.frame.size.width / self.number, 10);
        } else if ([view isKindOfClass:class]) {
            // system button
            CGRect frame = view.frame;
            int indexFromOrign = view.frame.origin.x/width;
            // 防止UIView *view in self.subviews 擷取到的不是有序的
            if (indexFromOrign >= (3 - 1) / 2) {
                indexFromOrign++;
            }
            CGFloat x = indexFromOrign * width;
            //如果是系統的UITabBarButton,那麼就調整子控件位置,空出中間位置
            view.frame = CGRectMake(x, view.frame.origin.y, width, frame.size.height);
            
            // 調整badge postion
            for (UIView *badgeView in view.subviews){
                NSString *className = NSStringFromClass([badgeView class]);
                // Looking for _UIBadgeView
                if ([className rangeOfString:@"BadgeView"].location != NSNotFound) {
                    badgeView.layer.transform = CATransform3DIdentity;
                    badgeView.layer.transform = CATransform3DMakeTranslation(-17.0, 1.0, 1.0);
                    break;
                }
            }
        }
    }
}


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    // 這一個判斷是關鍵,不判斷的話push到其他頁面,點選釋出按鈕的位置也是會有反應的,這樣就不好了
    // self.isHidden == NO 說明目前頁面是有tabbar的,那麼肯定是在導航控制器的根控制器頁面
    // 在導航控制器根控制器頁面,那麼我們就需要判斷手指點選的位置是否在釋出按鈕身上
    // 是的話讓釋出按鈕自己處理點選事件,不是的話讓系統去處理點選事件就可以了
    if (self.isHidden == NO) {
        // 将目前tabbar的觸摸點轉換坐标系,轉換到釋出按鈕的身上,生成一個新的點
        CGPoint newP = [self convertPoint:point toView:self.button];
        
        // 判斷如果這個新的點是在釋出按鈕身上,那麼處理點選事件最合适的view就是釋出按鈕
        if ( [self.button pointInside:newP withEvent:event]) {
            return self.button;
        } else {
            //如果點不在釋出按鈕身上,直接讓系統處理就可以了
            return [super hitTest:point withEvent:event];
        }
    } else {
        //tabbar隐藏了,那麼說明已經push到其他的頁面了,這個時候還是讓系統去判斷最合适的view處理就好了
        return [super hitTest:point withEvent:event];
    }
}

@end
           
@interface BaseTabBarController : UITabBarController

@property (nonatomic, copy) void (^showClick)(UIButton *button);

@end

#import "BaseTabBarController.h"
#import "MainVC.h"
#import "MineVC.h"
#import "AddVC.h"

#import "AddItemTabBar.h"

@interface BaseTabBarController () <AddItemTabBarDelegate, UITabBarControllerDelegate>

@property (nonatomic, strong) UIButton *addButton;

@end

@implementation BaseTabBarController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    //  自定義樣式
    [self initlizeAddItemController];
}

#pragma mark - 自定義tabbarItem

- (void)initlizeAddItemController
{
    [self setupVC];
    
    AddItemTabBar *tab = [[AddItemTabBar alloc] initWithFrame:CGRectZero];
    tab.number = 2;
    tab.delegate = self;
    [self setValue:tab forKey:@"tabBar"];
}

- (void)setupVC
{
    self.delegate = self;
    
    [self addChildVc:[[MainVC alloc] init] title:@"首頁" image:@"homeNormal" selectedImage:@"homeSelected"];
    [self addChildVc:[[MineVC alloc] init] title:@"我的" image:@"mineNormal" selectedImage:@"mineSelected"];
}

- (void)addChildVc:(UIViewController *)childVc title:(NSString *)title image:(NSString *)image selectedImage:(NSString *)selectedImage
{
    // 設定子控制器的文字(可以設定tabBar和navigationBar的文字)
    if (title) {
        childVc.title = title;
    }
    
    // 設定子控制器的tabBarItem圖檔
    if (image) {
        childVc.tabBarItem.image = [UIImage imageNamed:image];
    }
    
    // 禁用圖檔渲染
    if (selectedImage) {
        childVc.tabBarItem.selectedImage = [[UIImage imageNamed:selectedImage] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    }
    
    // 設定文字的樣式
    [childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]} forState:UIControlStateNormal];
    [childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor redColor]} forState:UIControlStateSelected];
    // 為子控制器包裝導航控制器
    UINavigationController *navigationVc = [[UINavigationController alloc] initWithRootViewController:childVc];
    // 添加子控制器
    [self addChildViewController:navigationVc];
}

- (void)tabBarItemClick:(UIButton *)button
{
    button.selected = !button.selected;
    if (self.addButton == nil) {
        self.addButton = button;
    }
    if (self.showClick) {
        self.showClick(button);
    }
}

#pragma mark - delegate

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
    if (self.addButton) {
        self.addButton.selected = NO;
    }

    UIApplication.sharedApplication.delegate.window.backgroundColor = [UIColor whiteColor];
    
    return YES;
}

@end
           
BaseTabBarController *rootVC = [[BaseTabBarController alloc] init];
    self.window.rootViewController = rootVC;
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    
    rootVC.showClick = ^(UIButton * _Nonnull button) {
        self.window.backgroundColor = [UIColor orangeColor];
    };
           

效果圖

UITabBarController的使用自定義UITabBar樣式