为你的TabBar添加Badge-感谢分享

本文介绍了一种自定义TabBar Badge的实现方法,通过定义Badge类型和提供API设置不同样式的Badge,包括红点和数字显示。文章详细介绍了实现过程和技术细节。
实现过程

首先定义了三种Badge类型

typedef NS_ENUM(NSUInteger, CustomBadgeType){
    kCustomBadgeStyleRedDot, //显示普通红点类型
    kCustomBadgeStyleNumber, //显示数字类型 kCustomBadgeStyleNone //不显示 };

然后提供了一个最主要的api, 设置badge

- (void)setBadgeStyle:(CustomBadgeType)type value:(NSInteger)badgeValue atIndex:(NSInteger)index;

下边是设置badge的实现, 主要思路是首先初始化所有的badgeView,比如tabbar items的数量为3,则初始化3个红点badge和数字badge,并把它们都隐藏。然后根据badge的style ,value,index设置显示哪一个红点以及显示什么样式。

-(void)setBadgeStyle:(CustomBadgeType)type value:(NSInteger)badgeValue atIndex:(NSInteger)index{
    //判断是否已经初始化过badge,没有的话则计算并添加badge
    if( ![[self valueForKey:kBadgeViewInitedKey] boolValue] ){ [self setValue:@(YES) forKey:kBadgeViewInitedKey]; [self addBadgeViews]; } //获取badge dotViews数组 和 numberViews数组, 分别代表红点badge和数字badge NSMutableArray *badgeDotViews = [self valueForKey:kBadgeDotViewsKey]; NSMutableArray *badgeNumberViews = [self valueForKey:kBadgeNumberViewsKey]; //设置隐藏badge [badgeDotViews[index] setHidden:YES]; [badgeNumberViews[index] setHidden:YES]; //根据类型决定显示哪一种badge if(type == kCustomBadgeStyleRedDot){ [badgeDotViews[index] setHidden:NO]; }else if(type == kCustomBadgeStyleNumber){ [badgeNumberViews[index] setHidden:NO]; UILabel *label = badgeNumberViews[index]; //根据数字来动态更新badge [self adjustBadgeNumberViewWithLabel:label number:badgeValue]; }else if(type == kCustomBadgeStyleNone){ //empty } }

这里初始化badgeViews的思路是使用tabbar的宽度计算出每一个badge的位置,然后添加UIView 和UILabel到tabbar中,并设置一些属性:

-(void)addBadgeViews{
    //获取badgeview的横向偏移量和top值
    id idIconWith = [self valueForKey:kTabIconWidth];
    CGFloat tabIconWidth = idIconWith ? [idIconWith floatValue] : 32; id idBadgeTop = [self valueForKey:kBadgeTop]; CGFloat badgeTop = idBadgeTop ? [idBadgeTop floatValue] : 11; NSInteger itemsCount = self.items.count; CGFloat itemWidth = self.bounds.size.width / itemsCount; //dotBadge views NSMutableArray *badgeDotViews = [NSMutableArray new]; for(int i = 0;i < itemsCount;i ++){ UIView *redDot = [UIView new]; redDot.bounds = CGRectMake(0, 0, 10, 10); redDot.center = CGPointMake(itemWidth*(i+0.5)+tabIconWidth/2, badgeTop); redDot.layer.cornerRadius = redDot.bounds.size.width/2; redDot.clipsToBounds = YES; redDot.backgroundColor = [UIColor redColor]; redDot.hidden = YES; [self addSubview:redDot]; [badgeDotViews addObject:redDot]; } //设置属性来记录有哪些dotViews,方便更新dotViews的属性时使用 [self setValue:badgeDotViews forKey:kBadgeDotViewsKey]; //numberBadge views NSMutableArray *badgeNumberViews = [NSMutableArray new]; for(int i = 0;i < itemsCount;i ++){ UILabel *redNum = [UILabel new]; redNum.layer.anchorPoint = CGPointMake(0, 0.5); redNum.bounds = CGRectMake(0, 0, 20, 14); redNum.center = CGPointMake(itemWidth*(i+0.5)+tabIconWidth/2-10, badgeTop); redNum.layer.cornerRadius = redNum.bounds.size.height/2; redNum.clipsToBounds = YES; redNum.backgroundColor = [UIColor redColor]; redNum.hidden = YES; redNum.textAlignment = NSTextAlignmentCenter; redNum.font = [UIFont systemFontOfSize:12]; redNum.textColor = [UIColor whiteColor]; [self addSubview:redNum]; [badgeNumberViews addObject:redNum]; } //设置属性来记录有哪些numberViews,方便更新numberViews的属性时使用 [self setValue:badgeNumberViews forKey:kBadgeNumberViewsKey]; }

上边还有一个函数是根据数字更新badge,实现也很简单武断,如下:

-(void)adjustBadgeNumberViewWithLabel:(UILabel *)label number:(NSInteger)number{
    [label setText:(number > 99 ? @"..." : @(number).stringValue)];
    if(number < 10){ label.bounds = CGRectMake(0, 0, 14, 14); }else if(number < 99){ label.bounds = CGRectMake(0, 0, 20, 14); }else{ label.bounds = CGRectMake(0, 0, 20, 14); } }

看完上边,其实大概的逻辑流程都讲清楚了。如果你细心的话,会发现[self setValue:badgeNumberViews forKey:kBadgeNumberViewsKey];这一句调用是有问题的,如果不处理程序会直接崩溃。我本来是想在extension中定义几个的属性,写起来才觉得很麻烦,因此在stackoverflow上稍微看了几个回答,采用了一个简单点的方法: 重写valueForUndefinedKey:setValue:forUndefinedKey:,并利用objc的动态绑定的方式注入属性,这里其实会有一些陷阱,可以参考我最后附的链接进行详细阅读。代码如下:

-(id)valueForUndefinedKey:(NSString *)key{
    return objc_getAssociatedObject(self, (__bridge const void *)(key)); } -(void)setValue:(id)value forUndefinedKey:(NSString *)key{ objc_setAssociatedObject(self, (__bridge const void *)(key), value, OBJC_ASSOCIATION_COPY); }

如果你知道更好地方法一定要告诉我 :- )

还有其他的一些api实现比较简单就不列出来了。

使用方法

使用方法相当简单,首先将github上的.h和.m文件加入你的工程,接下来只需要两步:

  1. 在初始化tabbar的时候,设置badgeview的位置
[tabController.tabBar setTabIconWidth:29];//调整x偏移量
[tabController.tabBar setBadgeTop:9];//调整y偏移量
  1. 设置显示badgeview的样式
[self.tabBarController.tabBar setBadgeStyle:type value:number atIndex:index];

大功告成!

效果

这里附上一个效果


demo.gif
思考

这个实现还有很多满足了我最简单的需求,还有一些问题需要处理:

  • 当tabbar更新时,badgeView并没有随着更新,这里需要添加一种自动的机制来更行
  • 还有一些其他的定制比如修改badgeView的颜色,修改badgeView的大小以及badgeView显示字符串而不仅仅是数字目前并没有支持 ,可能我比较懒吧,以后慢慢加上 :-)
参考

本文的源代码以及demo都在github上,需要的请戳这里 MRsummer/CustomBadge。欢迎吐槽~



文/summer朱光文(简书作者)
原文链接:http://www.jianshu.com/p/e8398e3231d5
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值