iOS开发-自定义TabbarController与Tabbar按钮Badge角标

iOS开发-自定义Tabbar按钮Badge角标

Tabbar是放在APP底部的控件。UITabbarController是一个非常常见的一种展示模式了。比如微信、QQ都是使用tabbar来进行功能分类的管理。
在这里插入图片描述

一、实现自定义Tabbar

我这里Tabbar继承于系统的UITabBar,定义背景图、线条的颜色、tabbarItem列表等属性

@property (nonatomic, strong) UIImage *bgroundImage;                //背景图
@property (nonatomic, strong) UIColor *lineColor;                   //线条的颜色
@property (nonatomic, strong) NSArray *dataSources;                 //tabbarItem列表
@property (nonatomic, assign) BOOL showLine;                        //线条的颜色
@property (nonatomic, assign) NSInteger selectedIndex;

SDTabBarDelegate协议,当点击了Tabbar某一个按钮,告知点击了index

@protocol SDTabBarDelegate <NSObject>

- (void)tabBar:(SDTabBar *)tabBar tabDidSelectedIndex:(NSInteger)index;

@end

代码如下

SDTabBar.h

#import <UIKit/UIKit.h>
#import "SDTabbarButton.h"

@protocol SDTabBarDelegate;
@interface SDTabBar : UITabBar

@property (nonatomic, weak) id<SDTabBarDelegate>tabDelegate;        //代理
@property (nonatomic, strong) UIImage *bgroundImage;                //背景图
@property (nonatomic, strong) UIColor *lineColor;                   //线条的颜色
@property (nonatomic, strong) NSArray *dataSources;                 //tabbarItem列表
@property (nonatomic, assign) BOOL showLine;                        //线条的颜色

@property (nonatomic, assign) NSInteger selectedIndex;              //选中的tabbar按钮index

- (instancetype)initWithFrame:(CGRect)frame;

/**
 更新tabbar样式

 @param tabbarItem item
 */
- (void)updateTabbarStyle:(SDTabbarItem *)tabbarItem;

@end

@protocol SDTabBarDelegate <NSObject>

- (void)tabBar:(SDTabBar *)tabBar tabDidSelectedIndex:(NSInteger)index;

@end

SDTabBar.m

#import "SDTabBar.h"
#import "SDBaseView.h"

static CGFloat kLineHeight = 1.0;
static CGFloat kPadding = 5.0;

@interface SDTabBar ()

@property (nonatomic, strong) UIImageView *bgImageView;
@property (nonatomic, strong) UIImageView *lineImageView;
@property (nonatomic, assign) CGFloat safeInsetBottom;

@end

@implementation SDTabBar

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self addSubview:self.bgImageView];
        [self addSubview:self.lineImageView];
        
        [self hidenTopLine];
        self.showLine = NO;
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.bgImageView.frame = self.bounds;
    self.safeInsetBottom = [SDBaseView baseSafeEdgeInsets].bottom;

    if (self.dataSources && self.dataSources.count > 0) {
        CGFloat width = CGRectGetWidth(self.bounds) / self.dataSources.count;
        CGFloat height = CGRectGetHeight(self.bounds);
        for (UIView *subView in self.subviews) {
            if ([subView isKindOfClass:[SDTabbarButton class]]) {
                SDTabbarButton *tabbarButton = (SDTabbarButton *)subView;
                CGRect imageBounds = CGRectMake(0.0, 0.0, width, height);
                CGPoint imageCenter = CGPointMake((tabbarButton.tag + 0.5) * width, height/2 - self.safeInsetBottom/2);
                tabbarButton.bounds = imageBounds;
                tabbarButton.center = imageCenter;
            }
        }
    }
    
    self.lineImageView.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(self.bgImageView.frame), kLineHeight);
    
    [self setTabbarSubview];
}

/**
 更新系统tabbar的选中状态
 */
- (void)updateTabbarButtons {
    for (UIView *subView in self.subviews) {
        if ([subView isKindOfClass:[SDTabbarButton class]]) {
            SDTabbarButton *tabbarButton = (SDTabbarButton *)subView;
            if (tabbarButton.tag == self.selectedIndex) {
                tabbarButton.selected = YES;
            } else {
                tabbarButton.selected = NO;
            }
        }
    }
}

/**
 隐藏系统的tabbarButton
 */
- (void)setTabbarSubview {
    for (UIView *child in self.subviews) {
        Class class = NSClassFromString(@"UITabBarButton");
        if ([child isKindOfClass:class]) {
            child.hidden = YES;
        }
    }
}

/**
 重新创建tabbarButtons
 */
- (void)setupTabbarButtons {
    
    for (UIView *subView in self.subviews) {
        if ([subView isKindOfClass:[SDTabbarButton class]]) {
            [subView removeFromSuperview];
        }
    }
    
    for (NSInteger index = 0; index < self.dataSources.count; index ++) {
        SDTabbarItem *tabbarItem = [self.dataSources objectAtIndex:index];
        SDTabbarButton *tabbarButton = [[SDTabbarButton alloc] initWithFrame:CGRectZero];
        tabbarButton.userInteractionEnabled = YES;
        tabbarButton.tabbarItem = tabbarItem;
        tabbarButton.tag = index;
        [tabbarButton addTarget:self action:@selector(tabbarButtonSelected:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:tabbarButton];
    }
    
    [self.bgImageView bringSubviewToFront:self.lineImageView];
    
    [self setNeedsLayout];
}

- (void)setDataSources:(NSArray *)dataSources {
    _dataSources = dataSources;
    [self setupTabbarButtons];
    [self setNeedsLayout];
}

- (void)setBgroundImage:(UIImage *)bgroundImage {
    _bgroundImage = bgroundImage;
    self.bgImageView.image = bgroundImage;
    [self setNeedsLayout];
}

- (void)setLineColor:(UIColor *)lineColor {
    _lineColor = lineColor;
    self.lineImageView.backgroundColor = lineColor;
    [self setNeedsLayout];
}

- (void)setShowLine:(BOOL)showLine {
    _showLine = showLine;
    self.lineImageView.hidden = !showLine;
    [self setNeedsLayout];
}

- (void)setSelectedIndex:(NSInteger)selectedIndex {
    _selectedIndex = selectedIndex;
    [self updateTabbarButtons];
    if (self.tabDelegate && [self.tabDelegate respondsToSelector:@selector(tabBar:tabDidSelectedIndex:)]) {
        [self.tabDelegate tabBar:self tabDidSelectedIndex:selectedIndex];
    }
}

/**
 更新tabbar样式
 
 @param tabbarItem item
 */
- (void)updateTabbarStyle:(SDTabbarItem *)tabbarItem {
    for (UIView *subView in self.subviews) {
        if ([subView isKindOfClass:[SDTabbarButton class]]) {
            SDTabbarButton *tabbarButton = (SDTabbarButton *)subView;
            SDTabbarItem *item = tabbarButton.tabbarItem;
            if (tabbarItem.identifier && [tabbarItem.identifier isEqualToString:item.identifier]) {
                //更新tabbar
                [item copyClone:tabbarItem];
                tabbarButton.tabbarItem = item;
                break;
            }
        }
    }
}

#pragma mark - Actions
- (void)tabbarButtonSelected:(SDTabbarButton *)tabbarButton {
    self.selectedIndex = tabbarButton.tag;
}

- (void)hidenTopLine {
    CGRect rect = [UIScreen mainScreen].bounds;
    UIGraphicsBeginImageContext(rect.size);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSetFillColorWithColor(context, [[UIColor clearColor] CGColor]);
    CGContextFillRect(context, rect);
    UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [self setBackgroundImage:img];
    [self setShadowImage:img];
}

#pragma mark - GETTER
- (UIImageView *)bgImageView {
    if (!_bgImageView) {
        _bgImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
        _bgImageView.backgroundColor = [UIColor clearColor];
        _bgImageView.clipsToBounds = YES;
    }
    return _bgImageView;
}

- (UIImageView *)lineImageView {
    if (!_lineImageView) {
        _lineImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
        _lineImageView.backgroundColor = [UIColor colorWithHexString:@"f3f3f3" alpha:1.0];
    }
    return _lineImageView;
}

@end

二、定义tabbar按钮

定义tabbar的按钮,定义显示的icon、标题、badge背景、badge显示等。

@property (nonatomic, strong) DFTabbarItem *tabbarItem;
@property (nonatomic, strong) UIImageView *iconImageView;
@property (nonatomic, strong) UIImageView *badgeImageView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *badgeLabel;

tabbar按钮SDTabbarButton

SDTabbarButton.h

#import <UIKit/UIKit.h>
#import "SDTabbarItem.h"

@interface SDTabbarButton : UIControl

@property (nonatomic, strong) SDTabbarItem *tabbarItem;

- (instancetype)initWithFrame:(CGRect)frame;

@end

SDTabbarButton.m

#import "SDTabbarButton.h"

static CGFloat kIconSize = 26.0;
static CGFloat kTitleHeight = 18.0;
static CGFloat kBadgeSize = 8.0;
static CGFloat kPadding = 5.0;
static CGFloat defaultBadgeRadius = 9.0;
static CGFloat defaultDotRadius = 5.0;

#define kTabbarDotShown @"dotShown"
#define kTabbarBadge @"badge"

@interface SDTabbarButton ()

@property (nonatomic, strong) UIImageView *iconImageView;
@property (nonatomic, strong) UIImageView *badgeImageView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *badgeLabel;

@end

@implementation SDTabbarButton

#pragma mark - INIT
- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self addSubview:self.iconImageView];
        [self addSubview:self.titleLabel];
        [self addSubview:self.badgeImageView];
        [self addSubview:self.badgeLabel];
    }
    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];
    
    CGSize titleSize = [self.titleLabel.text sizeWithFont:self.titleLabel.font forMaxSize:CGSizeMake(CGRectGetWidth(self.bounds), kTitleHeight)];
    
    CGFloat titleHeight = MIN(ceil(titleSize.height), kTitleHeight);
    
    self.iconImageView.frame = CGRectMake((CGRectGetWidth(self.bounds) - kIconSize)/2, (CGRectGetHeight(self.bounds) - kIconSize - titleHeight)/2, kIconSize, kIconSize);
    
    self.titleLabel.frame = CGRectMake(0.0, CGRectGetMaxY(self.iconImageView.frame), CGRectGetWidth(self.bounds), titleHeight);
    self.badgeImageView.frame = CGRectMake(CGRectGetMaxX(self.iconImageView.frame), CGRectGetMinY(self.iconImageView.frame) + kPadding, kBadgeSize, kBadgeSize);
    
    CGSize badgeSize = [self.badgeLabel.text sizeWithFont:self.badgeLabel.font forMaxSize:CGSizeMake(20.0, 20.0)];
    CGFloat minWidth = MAX(defaultBadgeRadius * 2, badgeSize.width + 10.0);
    CGFloat minHight = MAX(defaultBadgeRadius * 2, badgeSize.height);
    
    CGRect badgeBounds = CGRectMake(0.0, 0.0, minWidth, minHight);
    CGPoint badgeCenter = CGPointMake(CGRectGetMidX(self.iconImageView.frame) + CGRectGetHeight(badgeBounds), CGRectGetMidY(self.iconImageView.frame) - CGRectGetHeight(badgeBounds)/2 + 5.0);
    self.badgeLabel.bounds = badgeBounds;
    self.badgeLabel.center = badgeCenter;
    self.badgeLabel.layer.cornerRadius = minHight / 2;
}

#pragma mark - SETTER
- (void)setTabbarItem:(SDTabbarItem *)tabbarItem {
    _tabbarItem = tabbarItem;
    
    //设置icon
    self.iconImageView.image = tabbarItem.image;
    
    //设置标题
    self.titleLabel.font = tabbarItem.titleFont;
    self.titleLabel.textColor = tabbarItem.titleColor;
    self.titleLabel.text = [NSString stringWithFormat:@"%@",(tabbarItem.title?tabbarItem.title:@"")];

    //设置红点
    self.badgeImageView.hidden = !tabbarItem.dotShown;
    
    //设置badge
    self.badgeLabel.backgroundColor = tabbarItem.badgeColor;
    self.badgeLabel.text = [NSString stringWithFormat:@"%@",(tabbarItem.badge?tabbarItem.badge:@"")];
    if(tabbarItem.badge && tabbarItem.badge.length > 0) {
        self.badgeLabel.hidden = NO;
    } else {
        self.badgeLabel.hidden = YES;
    }
    
    [self addObserver];
    [self setNeedsLayout];
}

- (void)setSelected:(BOOL)selected {
    [super setSelected:selected];
    if (selected) {
        self.titleLabel.textColor = self.tabbarItem.selectedTitleColor;
        self.iconImageView.image = self.tabbarItem.selectedImage;
    } else {
        self.titleLabel.textColor = self.tabbarItem.titleColor;
        self.iconImageView.image = self.tabbarItem.image;
    }
}

#pragma mark - GETTER
- (UIImageView *)iconImageView {
    if (!_iconImageView) {
        _iconImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
        _iconImageView.backgroundColor = [UIColor clearColor];
        _iconImageView.contentMode = UIViewContentModeScaleAspectFit;
    }
    return _iconImageView;
}

- (UIImageView *)badgeImageView {
    if (!_badgeImageView) {
        _badgeImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
        _badgeImageView.backgroundColor = [UIColor clearColor];
        _badgeImageView.frame = CGRectMake(0.0, 0.0, kBadgeSize, kBadgeSize);
        _badgeImageView.layer.cornerRadius = kBadgeSize/2;
        _badgeImageView.layer.masksToBounds = YES;
        _badgeImageView.hidden = YES;
    }
    return _badgeImageView;
}

- (UILabel *)titleLabel {
    if (!_titleLabel) {
        _titleLabel = [[UILabel alloc]initWithFrame:CGRectZero];
        _titleLabel.backgroundColor = [UIColor clearColor];
        _titleLabel.textAlignment = NSTextAlignmentCenter;
    }
    return _titleLabel;
}

- (UILabel *)badgeLabel {
    if (!_badgeLabel) {
        _badgeLabel = [[UILabel alloc]initWithFrame:CGRectZero];
        _badgeLabel.backgroundColor = [UIColor clearColor];
        _badgeLabel.textAlignment = NSTextAlignmentCenter;
        _badgeLabel.clipsToBounds = YES;
        _badgeLabel.textColor = [UIColor whiteColor];
        _badgeLabel.font = [UIFont systemFontOfSize:12.0];
    }
    return _badgeLabel;
}

#pragma mark KVO Refresh
- (void)addObserver{
    @try {
        NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
        [self.tabbarItem addObserver:self forKeyPath:kTabbarDotShown options:options context:nil];
        [self.tabbarItem addObserver:self forKeyPath:kTabbarBadge options:options context:nil];
    } @catch (NSException *exception) {
        NSLog(@"exception:%@",exception);
    }
}

- (void)removeObserver{
    @try {
        [self.tabbarItem removeObserver:self forKeyPath:kTabbarDotShown context:nil];
        [self.tabbarItem removeObserver:self forKeyPath:kTabbarBadge context:nil];
    } @catch (NSException *exception) {
        NSLog(@"exception:%@",exception);
    }
}

//监听页面contentOffset
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if([kTabbarBadge isEqualToString:keyPath]) {
        NSString *badge = self.tabbarItem.badge;
        self.badgeLabel.text = [NSString stringWithFormat:@"%@",(badge?badge:@"")];
        if(badge && badge.length > 0) {
            self.badgeLabel.hidden = NO;
        } else {
            self.badgeLabel.hidden = YES;
        }
        return;
    }
    
    if ([kTabbarDotShown isEqualToString:keyPath]) {
        //设置红点
        self.badgeImageView.hidden = !self.tabbarItem.dotShown;
        return;
    }
}

- (void)dealloc {
    [self removeObserver];
}

@end

定义tabbarItem,确定icon、title、badge等

SDTabbarItem.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface SDTabbarItem : NSObject

@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) UIFont *titleFont;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) UIImage *selectedImage;
@property (nonatomic, strong) UIColor *titleColor;
@property (nonatomic, strong) UIColor *selectedTitleColor;
@property (nonatomic, strong) UIColor *badgeColor;
@property (nonatomic, strong) NSString *badge;
@property (nonatomic, assign) BOOL dotShown;

/**
 赋值

 @param item item
 */
- (void)copyClone:(SDTabbarItem *)item;

- (id)initWithTitle:(NSString *)title
          titleFont:(UIFont *)titleFont
              image:(UIImage *)image
      selectedImage:(UIImage *)selectedImage
         titleColor:(UIColor *)titleColor
 selectedTitleColor:(UIColor *)selectedTitleColor
         badgeColor:(UIColor *)badgeColor;

@end

SDTabbarItem.m

#import "SDTabbarItem.h"

@implementation SDTabbarItem

- (id)initWithTitle:(NSString *)title
          titleFont:(UIFont *)titleFont
              image:(UIImage *)image
      selectedImage:(UIImage *)selectedImage
         titleColor:(UIColor *)titleColor
 selectedTitleColor:(UIColor *)selectedTitleColor
         badgeColor:(UIColor *)badgeColor {
    self = [super init];
    if (self) {
        self.title = title;
        self.titleFont = titleFont;
        self.image = image;
        self.selectedImage = selectedImage;
        self.titleColor = titleColor;
        self.selectedTitleColor = selectedTitleColor;
        self.badge = [[NSString alloc] init];
        self.dotShown = NO;
        self.badgeColor = badgeColor;
    }
    return self;
}

/**
 赋值
 
 @param item item
 */
- (void)copyClone:(SDTabbarItem *)item {
    self.title = item.title;
    self.image = item.image;
    self.selectedImage = item.selectedImage;
    self.titleColor = item.titleColor;
    self.selectedTitleColor = item.selectedTitleColor;
    self.badgeColor = item.badgeColor;
}

@end

三、实现自定义TabbarController

在SDTabBarController的viewDidLoad执行[self setValue:_sdTabbar forKey:@“tabBar”];
注意:该方法替换TabbarController默认的tabbar

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    _sdTabbar = [[SDTabBar alloc] initWithFrame:CGRectZero];
    _sdTabbar.frame = self.tabBar.bounds;
    _sdTabbar.tabDelegate  = self;
    
    //UIImage *bgImage = [UIImage imageNamed:@"bg_tabbar"];
    UIImage *bgImage = [UIImage imageWithColor:[UIColor colorWithHexString:@"ffffff"] size:CGSizeMake(20, 20)];
    bgImage = [bgImage stretchableImageWithLeftCapWidth:bgImage.leftCapWidth*0.5 topCapHeight:bgImage.topCapHeight*0.5];
    _sdTabbar.bgroundImage = bgImage;

    _sdTabbar.backgroundImage = bgImage;

    [self setValue:_sdTabbar forKey:@"tabBar"];
}

SDTabBarController来控制tabbar元素点击对应的controller。

@property (nonatomic, strong) NSArray *tabViewControllers;

当点击按钮某一条时候,更改TabbarController的selectedIndex

- (void)tabBar:(SDTabBar *)tabBar tabDidSelectedIndex:(NSInteger)index {
    self.selectedIndex = index;
}

代码如下

SDTabBarController.h

#import <UIKit/UIKit.h>
#import "SDTabBar.h"

@interface SDTabBarController : UITabBarController<UINavigationControllerDelegate>

@property (nonatomic, strong, readonly) UINavigationController *selectedNavigationController;
@property (nonatomic, strong) NSArray *tabViewControllers;
@property (nonatomic, strong) SDTabBar *sdTabbar;

- (void)reset;

@end

SDTabBarController.m

#import "SDTabBarController.h"
#import "UIViewController+TabBarItem.h"

#define K_TAB_DEFAULT_INDEX  0

@interface SDTabBarController ()<SDTabBarDelegate>

@property (nonatomic, strong, readwrite) UINavigationController *selectedNavigation;

@end

@implementation SDTabBarController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    _sdTabbar = [[SDTabBar alloc] initWithFrame:CGRectZero];
    _sdTabbar.frame = self.tabBar.bounds;
    _sdTabbar.tabDelegate  = self;
    
    //UIImage *bgImage = [UIImage imageNamed:@"bg_tabbar"];
    UIImage *bgImage = [UIImage imageWithColor:[UIColor colorWithHexString:@"ffffff"] size:CGSizeMake(20, 20)];
    bgImage = [bgImage stretchableImageWithLeftCapWidth:bgImage.leftCapWidth*0.5 topCapHeight:bgImage.topCapHeight*0.5];
    _sdTabbar.bgroundImage = bgImage;

    _sdTabbar.backgroundImage = bgImage;

    [self setValue:_sdTabbar forKey:@"tabBar"];
}

#pragma mark - SETTER
- (void)setTabViewControllers:(NSArray *)tabViewControllers {
    _tabViewControllers = tabViewControllers;
    
    NSMutableArray *tabbarItems = [NSMutableArray arrayWithCapacity:0];
    for (UIViewController *viewController in tabViewControllers) {
        SDTabbarItem *item = nil;
        if ([viewController isKindOfClass:[UINavigationController class]]) {
            item = ((UIViewController *)((UINavigationController *)viewController).viewControllers.firstObject).sdTabbarItem;
        } else {
            item = viewController.sdTabbarItem;
        }
        [tabbarItems addObject:item];
    }
    
    self.sdTabbar.dataSources = tabbarItems;
    
    self.viewControllers = tabViewControllers;
    self.sdTabbar.selectedIndex = K_TAB_DEFAULT_INDEX;
}

#pragma mark - SDTabBarDelegate
- (void)tabBar:(SDTabBar *)tabBar tabDidSelectedIndex:(NSInteger)index {
    self.selectedIndex = index;
}

#pragma mark - reset
- (void)reset {
    if ([self.selectedViewController isKindOfClass:[UINavigationController class]]) {
        [self.selectedViewController popToRootViewControllerAnimated:NO];
    } else {
        [self.selectedViewController.navigationController popToRootViewControllerAnimated:NO];
    }
    
    [self.viewControllers enumerateObjectsUsingBlock:^(__kindof UIViewController * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj isKindOfClass:[UINavigationController class]]) {
            [(UINavigationController *)obj popToRootViewControllerAnimated:NO];
        }
    }];
    
    [self.sdTabbar setSelectedIndex:K_TAB_DEFAULT_INDEX];
}

- (NSUInteger)selectedIndex {
    return self.sdTabbar.selectedIndex;
}

- (UINavigationController *)selectedNavigationController {
    return (UINavigationController *)[self.tabViewControllers objectAtIndex:self.sdTabbar.selectedIndex];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

四、为UIViewController扩展属性TabBarItem

我这里为UIViewController扩展属性TabBarItem,方法TabbarController的viewControllers中的ViewController方法更改TabBarItem样式。

UIViewController+TabBarItem.h

#import <UIKit/UIKit.h>
#import "SDTabbarItem.h"

@interface UIViewController (TabBarItem)

@property (nonatomic, strong) SDTabbarItem *sdTabbarItem;

@end

UIViewController+TabBarItem.m

#import "UIViewController+TabBarItem.h"
#import <objc/runtime.h>

static const void *tabBarItemKey = &tabBarItemKey;

@implementation UIViewController (TabBarItem)

- (SDTabbarItem *)sdTabbarItem {
    return objc_getAssociatedObject(self, tabBarItemKey);
}

- (void)setSdTabbarItem:(SDTabbarItem *)sdTabbarItem {
    objc_setAssociatedObject(self, tabBarItemKey, sdTabbarItem, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

@end

五、使用自定义的Tabbar

使用SDMainTabBarController来继承SDTabBarController,配置viewControllers与按钮显示的TabbarItems

SDMainTabBarController.h

#import "SDTabBarController.h"

@interface SDMainTabBarController : SDTabBarController

- (void)clearBadgeNumber;

- (void)showTabBar:(BOOL)show;

@end

SDMainTabBarController.m

#import "SDMainTabBarController.h"
#import "UIViewController+TabBarItem.h"
#import "INMineViewController.h"
#import "INDiscoveryViewController.h"
#import "INAddressBookViewController.h"
#import "INConversationViewController.h"
#import "SDBaseNavigationController.h"
#import "UIColor+Addition.h"
#import "UIImage+Color.h"

#import "SDAppThemeDownloadManager.h"
#import "SDAppThemeManager.h"

@interface SDMainTabBarController ()

@property (nonatomic, strong) INMineViewController *mineVC;
@property (nonatomic, strong) INConversationViewController *conversationVC;
@property (nonatomic, strong) INAddressBookViewController *addressBookVC;
@property (nonatomic, strong) INDiscoveryViewController *discoveryVC;

@end

@implementation SDMainTabBarController

- (id)init {
    self  = [super init];
    if (self) {
        [self initControllers];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(systemAppThemeChanged:) name:K_APP_THEME_CHANGED object:nil];
    }
    return self;
}

- (void)initControllers {
    
    //我的
    self.mineVC = [[INMineViewController alloc] init];
    
    SDBaseNavigationController *mineNav = [[SDBaseNavigationController alloc] initWithRootViewController:self.mineVC];
    mineNav.delegate = self;
    
    //消息
    self.conversationVC = [[INConversationViewController alloc] init];
    SDBaseNavigationController *conversationNav = [[SDBaseNavigationController alloc] initWithRootViewController:self.conversationVC];
    conversationNav.delegate = self;
    
    //通讯录
    self.addressBookVC = [[INAddressBookViewController alloc] init];
    SDBaseNavigationController *addressBookNav = [[SDBaseNavigationController alloc] initWithRootViewController:self.addressBookVC];
    addressBookNav.delegate = self;
    
    //挖矿
    self.discoveryVC = [[INDiscoveryViewController alloc] init];
    SDBaseNavigationController *coinNav = [[SDBaseNavigationController alloc] initWithRootViewController:self.discoveryVC];
    coinNav.delegate = self;
    
    UIColor *titleColor = [UIColor colorWithHexString:@"B0B0B0"];
    
    UIColor *selectedColor = [UIColor colorWithHexString:@"171013"];
    
    UIColor *badgeColor = [UIColor colorWithHexString:@"FC3F51"];
    
    UIFont *titleFont = [UIFont systemFontOfSize:10];
    
    SDTabbarItem *item1 = [[SDTabbarItem alloc] initWithTitle:@"消息" titleFont:titleFont image:[UIImage imageNamed:@"ic_tab_home"] selectedImage:[UIImage imageNamed:@"ic_tab_home_selected"] titleColor:titleColor selectedTitleColor:selectedColor badgeColor:badgeColor];
    item1.identifier = @"home";
    self.conversationVC.sdTabbarItem = item1;
    
    SDTabbarItem *item2 = [[SDTabbarItem alloc] initWithTitle:@"通讯录" titleFont:titleFont image:[UIImage imageNamed:@"ic_tab_message"] selectedImage:[UIImage imageNamed:@"ic_tab_message_selected"] titleColor:titleColor selectedTitleColor:selectedColor badgeColor:badgeColor];
    item2.identifier = @"addressbook";
    self.addressBookVC.sdTabbarItem = item2;

    SDTabbarItem *item3 = [[SDTabbarItem alloc] initWithTitle:@"发现" titleFont:titleFont image:[UIImage imageNamed:@"ic_tab_discover"] selectedImage:[UIImage imageNamed:@"ic_tab_discover_selected"] titleColor:titleColor selectedTitleColor:selectedColor badgeColor:badgeColor];
    item3.identifier = @"discovery";
    self.discoveryVC.sdTabbarItem = item3;

    SDTabbarItem *item4 = [[SDTabbarItem alloc] initWithTitle:@"我的" titleFont:titleFont image:[UIImage imageNamed:@"ic_tab_profile"] selectedImage:[UIImage imageNamed:@"ic_tab_profile_selected"] titleColor:titleColor selectedTitleColor:selectedColor badgeColor:badgeColor];
    item4.identifier = @"mine";
    self.mineVC.sdTabbarItem = item4;

    self.tabViewControllers = @[conversationNav,addressBookNav,coinNav,mineNav];
        
    [self updateThemeConfig];
}

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)clearBadgeNumber {
    self.conversationVC.sdTabbarItem.badge = nil;
    self.addressBookVC.sdTabbarItem.badge = nil;
    self.discoveryVC.sdTabbarItem.badge = nil;
    self.mineVC.sdTabbarItem.badge = nil;
}

- (void)reset {
    [super reset];
}

- (void)updateThemeConfig {
    //主题,可以更改tabbar样式
    SDAppThemeConfigViewModel *themeConfigViewModel = [SDAppThemeManager shareInstance].configViewModel;
    
    UIImage *backgroundImage;
    if (themeConfigViewModel.tabbar.t_backgroundImage) {
        backgroundImage = themeConfigViewModel.tabbar.t_backgroundImage;
    } else {
        NSString *bgColor = themeConfigViewModel.tabbar.backgroundColor;
        backgroundImage = [UIImage imageWithColor:[UIColor colorWithHexString:bgColor] size:CGSizeMake(20.0, 20.0)];
        backgroundImage = [backgroundImage stretchableImageWithLeftCapWidth:backgroundImage.leftCapWidth*0.5 topCapHeight:backgroundImage.topCapHeight*0.5];
    }
    
    self.sdTabbar.bgroundImage = backgroundImage;
    
    NSString *showLine = themeConfigViewModel.tabbar.showLine;
    self.sdTabbar.showLine = [showLine boolValue];
    self.sdTabbar.lineColor = [UIColor colorWithHexString:themeConfigViewModel.tabbar.lineColor];
    
    UIColor *badgeBGColor = [UIColor colorWithHexString:themeConfigViewModel.tabbar.badgeBgColor];

    SDTabbarItem *homeItem = [self themeTabbarItem:themeConfigViewModel.tabbar.lianlian];
    homeItem.identifier = @"home";
    homeItem.badgeColor = badgeBGColor;
    
    SDTabbarItem *addressbookItem = [self themeTabbarItem:themeConfigViewModel.tabbar.message];
    addressbookItem.identifier = @"addressbook";
    addressbookItem.badgeColor = badgeBGColor;

    SDTabbarItem *discoveryItem = [self themeTabbarItem:themeConfigViewModel.tabbar.guangguang];
    discoveryItem.identifier = @"discovery";
    discoveryItem.badgeColor = badgeBGColor;

    SDTabbarItem *mineItem = [self themeTabbarItem:themeConfigViewModel.tabbar.mine];
    mineItem.identifier = @"mine";
    mineItem.badgeColor = badgeBGColor;

    [self.sdTabbar updateTabbarStyle:homeItem];
    [self.sdTabbar updateTabbarStyle:addressbookItem];
    [self.sdTabbar updateTabbarStyle:discoveryItem];
    [self.sdTabbar updateTabbarStyle:mineItem];
}

- (void)systemAppThemeChanged:(NSNotification *)notification {
    [self updateThemeConfig];
}

- (void)showTabBar:(BOOL)show {
    if (show != self.tabBar.hidden) {
        return;
    }
    
    UIView *subview= [self.view.subviews objectAtIndex:0];
    CGRect frame = subview.frame;
    CGRect tabBarFrame = self.tabBar.frame;
    
    if (show) {
        frame.size.height = kScreenHeight - self.tabBar.frame.size.height;
        tabBarFrame.origin.y = kScreenHeight - self.tabBar.frame.size.height;
    } else {
        frame.size.height = kScreenHeight;
        tabBarFrame.origin.y = kScreenHeight;
    }
    subview.frame = frame;
    self.tabBar.frame = tabBarFrame;
    self.tabBar.hidden = !show;
}

- (SDTabbarItem *)themeTabbarItem:(SDAppThemeConfigTabItemViewModel *)itemViewModel {
    SDTabbarItem *tabbarItem = [[SDTabbarItem alloc] init];
    tabbarItem.title = itemViewModel.title;
    tabbarItem.titleColor = [UIColor colorWithHexString:itemViewModel.titleColor];
    tabbarItem.selectedTitleColor = [UIColor colorWithHexString:itemViewModel.selectedTitleColor];
    tabbarItem.image = itemViewModel.t_icon;
    tabbarItem.selectedImage = itemViewModel.t_selectedIcon;
    return tabbarItem;
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end

这里的updateThemeConfig更改tabbar主题样式实现可以参考

https://blog.csdn.net/gloryFlow/article/details/132010193

六、小结

iOS开发-自定义Tabbar按钮Badge角标。Tabbar是放在APP底部的控件。UITabbarController是一个非常常见的一种展示模式了。比如微信、QQ都是使用tabbar来进行功能分类的管理。分别实现对应按钮、badge等

学习记录,每天不停进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/51896.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI编程常用工具 Jupyter Notebook

点击上方蓝色字体&#xff0c;选择“设为星标” 回复”云原生“获取基础架构实践 深度学习编程常用工具 我们先来看 4 个常用的编程工具&#xff1a;Sublime Text、Vim、Jupyter。虽然我介绍的是 Jupyter&#xff0c;但并不是要求你必须使用它&#xff0c;你也可以根据自己的喜…

VS Code环境配置问题

VS Code 环境配置问题 文章目录 VS Code 环境配置问题配置 C问题解决不乱码只显示结果避免闪退&#xff0c;中文乱码 配置 Java下载 JDKJDK 环境配置安装插件 配置 C 跟着官网教程&#xff08;英文版&#xff09;和其他博客配置了一遍&#xff0c;却遇到了很多小问题&#xff…

应用无线鼠标中的2.4GHz无线收发芯片

无线键盘和无线鼠标作为现代办公环境中常见的工具&#xff0c;为我们的工作带来了便利。无线键盘和无线鼠标的工作原理都是基于无线技术实现的&#xff0c;其中常见的是2.4GHz无线技术。让我们一起来详细了解一下它们的工作原理。 无线鼠标的原理非常简单,鼠标部分工作与传统鼠…

Spring中IOC容器常用的接口和具体的实现类

在Spring框架没有出现之前&#xff0c;在Java语言中&#xff0c;程序员们创建对象一般都是通过关键字new来完成&#xff0c;那时流行一句话“万物即可new&#xff0c;包括女朋友”。但是这种创建对象的方式维护成本很高&#xff0c;而且对于类之间的相互关联关系很不友好。鉴于…

【Tomcat---1】IDEA控制台tomcat日志输出乱码解决

一、修改IDEA的文件编码配置为UTF-8 二、修改IDEA的vmoptions文件&#xff0c;添加-Dfile.encodingUTF-8 到Tomcat目录/conf文件夹修改logging.properties 重启idea即可。采用统一的编码

解决在云服务器开放端口号以后telnet还是无法连接的问题

这里用阿里云服务器举例&#xff0c;在安全组开放了对应的TCP端口以后。使用windows的cmd下的telnet命令&#xff0c;还是无法正常连接。 telnet IP地址 端口号解决方法1&#xff1a; 在轻量服务器控制台的防火墙规则中添加放行端口。 阿里云-管理防火墙 如图&#xff0c;开放…

CAN转ETHERCAT网关将CAN 总线和 ETHERCAT 网络连接方法

由于好多现场会出现将CAN总线的设备接到EtherCAT网络中&#xff0c;由于协议的不相同&#xff0c;不能直接进行连接&#xff0c;现需一种能同时兼容CAN 总线和ETHERCAT网络的一种设备&#xff0c;由此捷米JM-ECT-CAN 是自主研发的一款 ETHERCAT 从站功能的通讯网关。该产品主要…

【目标检测论文解读复现NO.33】改进YOLOv5的新能源电池集流盘缺陷检测方法

前言 此前出了目标改进算法专栏&#xff0c;但是对于应用于什么场景&#xff0c;需要什么改进方法对应与自己的应用场景有效果&#xff0c;并且多少改进点能发什么水平的文章&#xff0c;为解决大家的困惑&#xff0c;此系列文章旨在给大家解读最新目标检测算法论文&#xff0c…

vuejs源码阅读之优化器

前面讲过vuejs中解析器是把html模版解析成AST&#xff0c;而优化器的作用是在AST中找到静态子树并打上标记。 静态子树是指的那些在AST中永远不会发生变化的节点。 例如&#xff0c;一个纯文本节点就是静态子树&#xff0c;而带变量的文本节点就不是静态子树&#xff0c;因为…

TCP网络通信编程之网络上传文件

【图片】 【思路解析】 【客户端代码】 import java.io.*; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException;/*** ProjectName: Study* FileName: TCPFileUploadClient* author:HWJ* Data: 2023/7/29 18:44*/ public class TCPFil…

如何快速模拟一个后端 API

第一步&#xff1a;创建一个文件夹&#xff0c;用来存储你的数据 数据&#xff1a; {"todos": [{ "id": 1, "text": "学习html44", "done": false },{ "id": 2, "text": "学习css", "…

【QT】Day 2

1> 继续完善登录框&#xff0c;当登录成功时&#xff0c;关闭登录界面&#xff0c;跳转到新的界面中 second.h #ifndef SECOND_H #define SECOND_H#include <QWidget>namespace Ui { class second; }class second : public QWidget {Q_OBJECTpublic:explicit second…

Abaqus 导出单元刚度矩阵和全局刚度矩阵

Abaqus 导出单元刚度矩阵和全局刚度矩阵 首次创建&#xff1a;2023.7.29 最后更新&#xff1a;2023.7.29 如有什么改进的地方&#xff0c;欢迎大家讨论&#xff01; 详细情况请查阅&#xff1a;Abaqus Analysis User’s Guide 一、Abaqus 导出单元刚度矩阵 1.生成单元刚度矩阵…

C语言手撕顺序表

目录 一、概念 1、静态顺序表&#xff1a;使用定长数组存储元素。 2、动态顺序表&#xff1a;使用动态开辟的数组存储 二、接口实现 1、对顺序表的初始化 2、对数据的销毁 3、对数据的打印 4、检查是否需要扩容 5、尾插 6、头插 7、尾删 8、头删 9、在pos位置插入x …

如何有效地使用ChatGPT写小说讲故事?

​构思故事情节&#xff0c;虽有趣但耗时&#xff0c;容易陷入写作瓶颈。ChatGPT可提供灵感&#xff0c;帮你解决写作难题。要写出引人入胜的故事&#xff0c;关键在于抓住八个要素——主题、人物、视角、背景、情节、语气、冲突和解决办法。 直接给出故事模板&#xff0c;你可…

WIZnet W5500-EVB-Pico 静态IP配置教程(二)

W5500是一款高性价比的 以太网芯片&#xff0c;其全球独一无二的全硬件TCP、IP协议栈专利技术&#xff0c;解决了嵌入式以太网的接入问题&#xff0c;简单易用&#xff0c;安全稳定&#xff0c;是物联网设备的首选解决方案。WIZnet提供完善的配套资料以及实时周到的技术支持服务…

TCP网络通信编程之字节流

目录 【TCP字节流编程】 // 网络编程中&#xff0c;一定是server端先运行 【案例1】 【思路分析】 【客户端代码】 【服务端代码】 【结果展示】 【案例2】 【题目描述】 【注意事项】 【服务端代码】 【客户端代码】 【代码结果】 【TCP字节流编程】 // 网络编程中&a…

《向量数据库指南》——Milvus Cloud2.2.12 易用性,可视化,自动化大幅提升

Milvus Cloud又迎版本升级,三大新特性全力加持,易用性再上新台阶! 近期,Milvus Cloud上线了 2.2.12 版本,此次更新不仅一次性增加了支持 Restful API、召回原始向量、json_contains 函数这三大特性,还优化了 standalone 模式下的 CPU 使用、查询链路等性能,用一句话总…

Mysql定时删除表数据

由于用户环境有张日志表每天程序都在狂插数据&#xff0c;导致不到一个月时间&#xff0c;这张日志表就高达200多万条记录&#xff0c;但是日志刷新较快&#xff0c;里面很多日志没什么作用&#xff0c;就写了个定时器&#xff0c;定期删除这张表的数据。 首先查看mysql是否开启…

银河麒麟安装mysql数据库(mariadb)-银河麒麟安装JDK-银河麒麟安装nginx(附安装包)

银河麒麟离线全套安装教程&#xff08;手把手教程&#xff09; 1.银河麒麟服务器系统安装mysql数据库&#xff08;mariadb&#xff09; 2.银河麒麟桌面系统安装mysql数据库&#xff08;mariadb&#xff09; 3.银河麒麟服务器系统安装JDK 4.银河麒麟桌面系统安装JDK 5.银河麒麟…