自定义的TabBar
这是一个老生常谈的就问题,写在这里只是为了做一下笔记
实现类似下图的问题
废话不多说,直接上代码
首先自定义一个tabbar 继承与 UITabBar
.h
#import <UIKit/UIKit.h> //tab页面个数 typedef NS_ENUM(NSInteger, SamItemUIType) { SamItemUIType_Three = 3,//底部3个选项 SamItemUIType_Five = 5,//底部5个选项 }; @class BaseTabBar; @protocol SamTabBarDelegate <NSObject> -(void)tabBar:(BaseTabBar *)tabBar clickCenterButton:(UIButton *)sender; @end @interface BaseTabBar : UITabBar @property (nonatomic, weak) id<SamTabBarDelegate> tabDelegate; @property (nonatomic, strong) NSString *centerBtnTitle; @property (nonatomic, strong) NSString *centerBtnIcon; +(instancetype)instanceCustomTabBarWithType:(SamItemUIType)type; @end
.m
#import "BaseTabBar.h" @interface BaseTabBar() @property(nonatomic, strong) UIButton *centerButton; @property(nonatomic, strong) UILabel *centerTitle; @property (nonatomic,assign) SamItemUIType type; @end @implementation BaseTabBar +(instancetype)instanceCustomTabBarWithType:(SamItemUIType)type{ BaseTabBar *tabBar = [[BaseTabBar alloc] init]; tabBar.type = type; return tabBar; } -(instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { self.translucent = NO; UIButton *plusBtn = [UIButton buttonWithType:UIButtonTypeCustom]; self.centerButton = plusBtn; [plusBtn addTarget:self action:@selector(plusBtnDidClick) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:plusBtn]; UILabel *lblTitle = [[UILabel alloc] init]; self.centerTitle = lblTitle; lblTitle.font = [UIFont systemFontOfSize:10]; lblTitle.textColor = [UIColor blackColor]; lblTitle.textAlignment = NSTextAlignmentCenter; [self addSubview:lblTitle]; } return self; } -(void)plusBtnDidClick{ if (self.tabDelegate && [self.tabDelegate respondsToSelector:@selector(tabBar:clickCenterButton:)]) { [self.tabDelegate tabBar:self clickCenterButton:self.centerButton]; } } // 调整子视图的布局 -(void)layoutSubviews{ [super layoutSubviews]; CGFloat width = self.frame.size.width/self.type; Class class = NSClassFromString(@"UITabBarButton"); for (UIView *view in self.subviews) { if ([view isEqual:self.centerTitle]) {//self.centerButton view.frame = CGRectMake(0, 0, width, 15); view.center = CGPointMake(self.frame.size.width/2, self.frame.size.height - view.frame.size.height + 8); }else if ([view isEqual:self.centerButton]) {//self.centerButton view.frame = CGRectMake(0, 0, width, self.frame.size.height); [view sizeToFit]; view.center = CGPointMake(self.frame.size.width/2, 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 >= (self.type - 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.centerButton]; //判断如果这个新的点是在发布按钮身上,那么处理点击事件最合适的view就是发布按钮 if ( [self.centerButton pointInside:newP withEvent:event]) { return self.centerButton; }else{//如果点不在发布按钮身上,直接让系统处理就可以了 return [super hitTest:point withEvent:event]; } } else {//tabbar隐藏了,那么说明已经push到其他的页面了,这个时候还是让系统去判断最合适的view处理就好了 return [super hitTest:point withEvent:event]; } } -(void)setCenterBtnIcon:(NSString *)centerBtnIcon{ _centerBtnIcon = centerBtnIcon; [self.centerButton setBackgroundImage:[UIImage imageNamed:self.centerBtnIcon] forState:UIControlStateNormal]; [self.centerButton setBackgroundImage:[UIImage imageNamed:self.centerBtnIcon] forState:UIControlStateHighlighted]; } -(void)setCenterBtnTitle:(NSString *)centerBtnTitle{ _centerBtnTitle = centerBtnTitle; self.centerTitle.text = centerBtnTitle; } @end
然后写一个继承与UITabBarController的Controller
#import "RootTabBarViewController.h" #import "BaseTabBar.h" #import "FirstViewController.h" #import "BaseNaViewController.h" #import "SecondViewController.h" #import "UITabBar+BadgeOfTabBar.h" @interface RootTabBarViewController ()<SamTabBarDelegate> @end @implementation RootTabBarViewController - (void)viewDidLoad { [super viewDidLoad]; [self setupUI]; } -(void)setupUI{ [self setupVC]; [[UITabBar appearance] setShadowImage:[UIImage new]]; //kvo形式添加自定义的 UITabBar BaseTabBar *tab = [BaseTabBar instanceCustomTabBarWithType:SamItemUIType_Five]; tab.centerBtnTitle = @"发布"; tab.centerBtnIcon = @"icon_toolview_add_normal"; tab.tabDelegate = self; [self setValue:tab forKey:@"tabBar"]; } - (void)setupVC{ [self addChildVc:[[FirstViewController alloc] init] title:@"首页" image:@"four-off" selectedImage:@"four-on"]; [self addChildVc:[[FirstViewController alloc] init] title:@"发现" image:@"four-off" selectedImage:@"four-on"]; [self addChildVc:[[FirstViewController alloc] init] title:@"消息" image:@"four-off" selectedImage:@"four-on"]; [self addChildVc:[[FirstViewController alloc] init] title:@"个人中心" image:@"four-off" selectedImage:@"four-on"]; } - (void)addChildVc:(UIViewController *)childVc title:(NSString *)title image:(NSString *)image selectedImage:(NSString *)selectedImage{ // 设置子控制器的文字(可以设置tabBar和navigationBar的文字) childVc.title = title; // 设置子控制器的tabBarItem图片 childVc.tabBarItem.image = [UIImage imageNamed:image]; // 禁用图片渲染 childVc.tabBarItem.selectedImage = [[UIImage imageNamed:selectedImage] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; // 设置文字的样式 [childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]} forState:UIControlStateNormal]; [childVc.tabBarItem setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor redColor]} forState:UIControlStateSelected]; // 为子控制器包装导航控制器 BaseNaViewController *navigationVc = [[BaseNaViewController alloc] initWithRootViewController:childVc]; // 添加子控制器 [self addChildViewController:navigationVc]; } -(void)tabBar:(BaseTabBar *)tabBar clickCenterButton:(UIButton *)sender{ // UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"点击了中间按钮" preferredStyle:UIAlertControllerStyleAlert]; // UIAlertAction *action = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { // // }]; // [alert addAction:action]; // [self presentViewController:alert animated:YES completion:nil]; SecondViewController *sec = [[SecondViewController alloc] init]; UIViewController *vc = [self topVC:[UIApplication sharedApplication].keyWindow.rootViewController]; sec.hidesBottomBarWhenPushed = YES; [vc.navigationController pushViewController:sec animated:YES]; } - (UIViewController *)topVC:(UIViewController *)rootViewController{ if ([rootViewController isKindOfClass:[UITabBarController class]]) { UITabBarController *tab = (UITabBarController *)rootViewController; return [self topVC:tab.selectedViewController]; }else if ([rootViewController isKindOfClass:[UINavigationController class]]){ UINavigationController *navc = (UINavigationController *)rootViewController; return [self topVC:navc.visibleViewController]; }else if (rootViewController.presentedViewController){ UIViewController *pre = (UIViewController *)rootViewController.presentedViewController; return [self topVC:pre]; }else{ return rootViewController; } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
再写一个子控制器继承与UINavigationController 里面不需要写代码
为tabbar添加小红点
为UITabBar 写一个类别
#import <UIKit/UIKit.h> @interface UITabBar (BadgeOfTabBar) - (void)showBadgeOnItmIndex:(int)index tabbarNum:(int)tabbarNum; -(void)hideBadgeOnItemIndex:(int)index; - (void)removeBadgeOnItemIndex:(int)index; @end
#import "UITabBar+BadgeOfTabBar.h" @implementation UITabBar (BadgeOfTabBar) - (void)showBadgeOnItmIndex:(int)index tabbarNum:(int)tabbarNum{ [self removeBadgeOnItemIndex:index]; //label为小红点,并设置label属性 UILabel *label = [[UILabel alloc]init]; label.tag = 1000+index; label.layer.cornerRadius = 5; label.clipsToBounds = YES; label.backgroundColor = [UIColor redColor]; CGRect tabFrame = self.frame; //计算小红点的X值,根据第index控制器,小红点在每个tabbar按钮的中部偏移0.1,即是每个按钮宽度的0.6倍 CGFloat percentX = (index+0.6); CGFloat tabBarButtonW = CGRectGetWidth(tabFrame)/tabbarNum; CGFloat x = percentX*tabBarButtonW; CGFloat y = 0.1*CGRectGetHeight(tabFrame); //10为小红点的高度和宽度 label.frame = CGRectMake(x, y, 10, 10); [self addSubview:label]; //把小红点移到最顶层 [self bringSubviewToFront:label]; } -(void)hideBadgeOnItemIndex:(int)index{ [self removeBadgeOnItemIndex:index]; } - (void)removeBadgeOnItemIndex:(int)index{ for (UIView*subView in self.subviews) { if (subView.tag == 1000+index) { [subView removeFromSuperview]; } } } @end
调用方法,在要使用的放引入类别,我这里写在VC里面了
tabbarNum 指的是有几个Tabbar index指的是 第几个按钮添加小红点
[self.tabBarController.tabBar showBadgeOnItmIndex:3 tabbarNum:5];
over!