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
效果圖

方法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];
};
效果圖