iOS OC-自定义TabBar TabBarViewController

  前段时间,我们产品同学又提了个需求。咳咳,就是想要服务器动态控制tabBar的图片和文字,而且要兼容文字没有的情况下图片撑满,而且图片的显示范围固定。但是系统自带的tabBarItem我试了下是不能固定图片显示范围的,它是根据图片的大小来适应的。所有我就自定义了一套,最终效果如下(最后有demo地址):


QQ20180726-134906-HD.gif
1、自定义tabBarItem
@interface CYXTabBarItem : UIView
/*未选中的图片*/
@property (nonatomic,strong) UIImage *image;
/*选中的图片*/
@property (nonatomic,strong) UIImage *selectedImage;
/*标题*/
@property (nonatomic,copy) NSString *title;
/*是否是选中*/
@property (nonatomic,assign) BOOL selected;
/*最大图片尺寸*/
@property (nonatomic,assign) CGSize maxImageSize;
/*最小图片尺寸*/
@property (nonatomic,assign) CGSize minImageSize;
/*文字颜色*/
@property (nonatomic,strong) UIColor *titleColor;
/*选中的文字颜色*/
@property (nonatomic,strong) UIColor *selectedTitleColor;
/*点击*/
@property (nonatomic,strong) void(^selectBlock)(void);
/*更新布局方法 设置完之后记得调用*/
-(void)updateImageAndTitle;
@end

implementation:

@interface CYXTabBarItem()
/*图片*/
@property (nonatomic,strong) UIImageView *imageView;
/*文字*/
@property (nonatomic,strong) UILabel *titleLabel;
@end
@implementation CYXTabBarItem
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self addSubview:self.imageView];
        [self addSubview:self.titleLabel];
        [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
            make.height.mas_equalTo(11);
            make.left.and.right.equalTo(self);
            make.top.equalTo(self).offset(35);
        }];
        __weak __typeof(self) _self = self;
        [self setTapActionWithBlock:^{
            if (_self.selectBlock) {
                _self.selectBlock();
            }
        }];
    }
    return self;
}
/*更新布局方法 设置完之后记得调用*/
-(void)updateImageAndTitle{
    self.titleLabel.text = self.title;
    if (self.selected) {
        self.titleLabel.font = [UIFont systemFontOfSize:10.0];
        self.titleLabel.textColor = self.selectedTitleColor;
        if (self.selectedImage) {
            self.imageView.image = self.selectedImage;
        }
    }else{
        self.titleLabel.font = [UIFont boldSystemFontOfSize:10.0];
        self.titleLabel.textColor = self.titleColor;
        if (self.image) {
            self.imageView.image = self.image;
        }
    }
    if ([self.title length]) {
        [self.imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.height.and.width.mas_equalTo(22);
            make.centerX.equalTo(self);
            make.top.equalTo(self).offset(5);
        }];
    }else{
        [self.imageView mas_remakeConstraints:^(MASConstraintMaker *make) {
            make.height.and.width.mas_equalTo(40);
            make.centerX.equalTo(self);
            make.top.equalTo(self).offset(5);
        }];
    }
}
#pragma mark ---G
-(UIImageView*)imageView{
    if(!_imageView){
        _imageView = [[UIImageView alloc] init];
    }
    return _imageView;
}
-(UILabel*)titleLabel{
    if(!_titleLabel){
        _titleLabel = [[UILabel alloc] init];
        _titleLabel.font = [UIFont systemFontOfSize:10];
        _titleLabel.textColor = [UIColor grayColor];
        _titleLabel.textAlignment = NSTextAlignmentCenter;
    }
    return _titleLabel;
}
2、自定义tabBarView
@interface CYXBarView : UIView

/*初始化按钮*/
-(void)initButtonWithViewControllers:(NSArray<UIViewController *> * )viewControllers;
/*最大图片尺寸*/
@property (nonatomic,assign) CGSize maxImageSize;
/*最小图片尺寸*/
@property (nonatomic,assign) CGSize minImageSize;
/*文字颜色*/
@property (nonatomic,strong) UIColor *titleColor;
/*选中的文字颜色*/
@property (nonatomic,strong) UIColor *selectedTitleColor;
/*点击*/
@property (nonatomic,strong) void(^selectBlock)(NSInteger index);
@property (nonatomic, assign) NSInteger selectIndex;
@end

implementation:

@interface CYXBarView()


@property (nonatomic,strong) NSMutableArray<CYXTabBarItem *> *items;
@end
@implementation CYXBarView
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.maxImageSize = CGSizeMake(40, 40);
        self.minImageSize = CGSizeMake(20, 20);
        self.titleColor = [UIColor grayColor];
        self.selectedTitleColor = [UIColor redColor];
        self.items = [NSMutableArray new];
    }
    
    return self;
}

-(void)initButtonWithViewControllers:(NSArray<UIViewController *> * )viewControllers{
    [self.items removeAllObjects];
    
    for (UIView * view in self.subviews) {
        [view removeFromSuperview];
    }
    CGFloat  itemWidth =screenWidth/viewControllers.count;
    for (int i= 0; i<viewControllers.count; i++) {
        CYXTabBarItem * item = [[CYXTabBarItem alloc] init];
        item.maxImageSize = self.maxImageSize;
        item.minImageSize = self.minImageSize;
        item.titleColor = self.titleColor;
        item.selectedTitleColor = self.selectedTitleColor;
        UIViewController * viewController = viewControllers[i];
        item.title = [viewController.tabBarItem.title length]?viewController.tabBarItem.title:viewController.title;
        item.selectedImage = viewController.tabBarItem.selectedImage;
        item.image = viewController.tabBarItem.image;
        [self addSubview:item];
        [item mas_makeConstraints:^(MASConstraintMaker *make) {
            make.width.mas_equalTo(itemWidth);
            make.height.equalTo(self);
            make.top.equalTo(self);
            make.left.mas_equalTo(i*itemWidth);
        }];
        
        [self.items addObject:item];
        __weak __typeof(self) _self = self;
        item.selectBlock = ^{
            _self.selectIndex = i;
            if (_self.selectBlock) {
                _self.selectBlock(_self.selectIndex);
            }
        };
        [item updateImageAndTitle];
    }
    self.selectIndex = 0;
}
- (void)setSelectIndex:(NSInteger)selectIndex
{
    if (![self.items count]||selectIndex>=[self.items count]) {return;}
    // 先把上次选择的item设置为可用
    CYXTabBarItem *lastItem = self.items[_selectIndex];
    lastItem.selected = NO;
    // 再把这次选择的item设置为不可用
    CYXTabBarItem *item = self.items[selectIndex];
    item.selected = YES;
    _selectIndex = selectIndex;
    [lastItem updateImageAndTitle];
    [item updateImageAndTitle];
}
@end
2、自定义tabBar
@class CYXBarView;
@interface CYXTabBar : UITabBar

@property (nonatomic,strong) CYXBarView *tabBarView;

@end

implementation:

@interface CYXTabBar ()

@end
@implementation CYXTabBar
- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self addSubview:self.tabBarView];
        [self.tabBarView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.and.right.and.left.and.bottom.equalTo(self);
        }];
        
    }
    
    return self;
}
- (void)layoutSubviews
{
    [super layoutSubviews];
    // 把tabBarView带到最前面,覆盖tabBar的内容
    [self bringSubviewToFront:self.tabBarView];
    /*隐藏原来的*/
    for (UIView *view in self.subviews) {
        if ([view isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
            view.hidden = YES;
        }
    }
    
}
// 重写hitTest方法,让超出tabBar部分也能响应事件
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if (self.clipsToBounds || self.hidden || (self.alpha == 0.f)) {
        return nil;
    }
    UIView *result = [super hitTest:point withEvent:event];
    // 如果事件发生在tabbar里面直接返回
    if (result) {
        return result;
    }
    // 这里遍历那些超出的部分就可以了,不过这么写比较通用。
    for (UIView *subview in self.tabBarView.subviews) {
        // 把这个坐标从tabbar的坐标系转为subview的坐标系
        CGPoint subPoint = [subview convertPoint:point fromView:self];
        result = [subview hitTest:subPoint withEvent:event];
        // 如果事件发生在subView里就返回
        if (result) {
            return result;
        }
    }
    return nil;
}
#pragma mark ---G
-(CYXBarView*)tabBarView{
    if(!_tabBarView){
        _tabBarView = [[CYXBarView alloc] init];
    }
    return _tabBarView;
}
2、自定义UITabBarController
@interface CYXTabBarViewController : UITabBarController

@end

implementation:

@interface CYXTabBarViewController ()
@property (nonatomic,strong) CYXTabBar *customTabBar;
@end

@implementation CYXTabBarViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self setValue:self.customTabBar forKey:@"tabBar"];
    
    [self initViewControllers];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.selectedIndex = 3;
    });
}
-(void)initViewControllers{
    NSMutableArray * viewControllers = [NSMutableArray new];
    UIViewController *homeVC = [[UIViewController alloc] init];
    homeVC.view.backgroundColor = [UIColor redColor];
    [viewControllers addObject:[self addChildViewController:homeVC title:@"首页" imageNamed:@"tabBar_home"]];
    
    UIViewController *expoVC = [[UIViewController alloc] init];
    expoVC.view.backgroundColor = [UIColor yellowColor];
    [viewControllers addObject:[self addChildViewController:expoVC title:@"家博会" imageNamed:@"tabBar_activity"]];
    
    UIViewController *activityVC = [[UIViewController alloc] init];
    activityVC.view.backgroundColor = [UIColor yellowColor];
    [viewControllers addObject:[self addChildViewController:activityVC title:@"" imageNamed:@"tabBar_activity"]];
    
    UIViewController *findVC = [[UIViewController alloc] init];
    findVC.view.backgroundColor = [UIColor blueColor];
    [viewControllers addObject:[self addChildViewController:findVC title:@"发现" imageNamed:@"tabBar_find"]];
    
    UIViewController *mineVC = [[UIViewController alloc] init];
    mineVC.view.backgroundColor = [UIColor greenColor];
    [viewControllers addObject:[self addChildViewController:mineVC title:@"我的" imageNamed:@"tabBar_mine"]];
    
    self.viewControllers = viewControllers;
}
// 添加某个 childViewController
- (UINavigationController *)addChildViewController:(UIViewController *)vc title:(NSString *)title imageNamed:(NSString *)imageNamed
{
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
    // 如果同时有navigationbar 和 tabbar的时候最好分别设置它们的title
    vc.navigationItem.title = title;
    nav.tabBarItem.title = title;
    nav.tabBarItem.image = [UIImage imageNamed:imageNamed];
    nav.tabBarItem.selectedImage = [UIImage imageNamed:@"jmtIconBg"];
    return nav;
}

-(void)setViewControllers:(NSArray<__kindof UIViewController *> *)viewControllers{
    [super setViewControllers:viewControllers];
    [self.customTabBar.tabBarView initButtonWithViewControllers:viewControllers];
}
-(void)setSelectedIndex:(NSUInteger)selectedIndex{
    [super setSelectedIndex:selectedIndex];
    self.customTabBar.tabBarView.selectIndex = selectedIndex;
}
#pragma mark ---G
-(CYXTabBar*)customTabBar{
    if(!_customTabBar){
        _customTabBar = [[CYXTabBar alloc] init];
        __weak __typeof(self) _self = self;
        _customTabBar.tabBarView.selectBlock = ^(NSInteger index) {
             _self.selectedIndex = index;
        };
    }
    return _customTabBar;
}

Appdelegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.backgroundColor = [UIColor whiteColor];
    self.window.rootViewController = [[CYXTabBarViewController alloc] init];
    // 设置这个窗口有主窗口并显示
    [self.window makeKeyAndVisible];
    return YES;
}

这样就实现上图所示效果图了,高度自定义化,可随意修改。欢迎讨论指教
demo:https://github.com/SionChen/CYXCustomTabBarController

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350