UITabBarController的使用过程中,可能会出现需要自定义UITabBar样式的时候,下面介绍两种实现方法。
方法1
存在N个视图控制器,且需要使用自定义的UITabBar样式来进行交互操作哪个视图控制器的显示。具体做法是在UITabBarController中的view中添加自定义样式的子视图,设置子视图响应方法跳转对应的视图控制器,然后再通过UITabBarController的代理方法重置自定义样式的子视图状态。
代码示例,继承UITabBarController的方式实现
#import "BaseTabBarController.h"
#import "MainVC.h"
#import "MineVC.h"
#import "AddVC.h"
@interface BaseTabBarController ()
@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
@protocol AddItemTabBarDelegate
- (void)tabBarItemClick:(UIButton *)button;
@end
@interface AddItemTabBar : UITabBar
@property (nonatomic, weak) iddelegate;
@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 ()
@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];
};