自定义的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!

 

posted @ 2018-07-16 12:57  NSJELLY  阅读(176)  评论(0编辑  收藏  举报