实现过程

首先定义了三种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
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

为你的TabBar添加Badge-感谢分享的更多相关文章

  1. Android中通过ActionBar为标题栏添加搜索以及分享视窗

    在Android3.0之后,Google对UI导航设计上进行了一系列的改革,其中有一个非常好用的新功能就是引入的ActionBar,他用于取代3.0之前的标题栏,并提供更为丰富的导航效果.Action ...

  2. Ext TabPanel tabbar添加按钮

    tabPanel tabbar添加按钮 this.tabPanel = Ext.create('Ext.tab.Panel', { tabBar:{ items:[{ //组件靠右 xtype: 't ...

  3. mysql启动关闭的批处理,感觉很好用在其他论坛帖子上找到的,感谢分享

    最近用mysql的时间比较多,每次都在计算机管理工具下面去启动,感觉很麻烦,于是搜索了下果然有前辈已经做出了这些东西,今天收藏整理,mysql启动关闭的批处理感觉很好用在其他论坛帖子上找到的,感谢互联 ...

  4. Cocos2d-x 添加iOS7默认分享/AirDrop

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2D开发网–Cocos2Dev.com,谢谢! 原文地址: http://www.cocos2dev.com/?p=530 下午添加分享的时候,看着这 ...

  5. 应用程序添加角标和tabBar添加角标,以及后台运行时显示

    1.设置角标的代码:   // 从后台取出来的数据可能是int型的不能直接给badgeValue(string类型的),需要通过description转化  NSString *count = [re ...

  6. iOS TabBar添加阴影

    效果图如下所示: 直接上代码 //移除顶部线条 self.tabBar.backgroundImage = [UIImage new]; self.tabBar.shadowImage = [UIIm ...

  7. flutter 自定义tabbar 给tabbar添加背景功能

    flutter 自带的tabbar BottomNavigationBar有长按水波纹效果,不可以添加背景图片功能,如果有这方面的需求,就需要自定义tabbar了 自定义图片 我们使用BottomAp ...

  8. iOS 实现脉冲雷达以及动态增减元素 By Swift-感谢分享

    Swift经过Xcode6 Beta4一版更新后,基本上已经可以作为生产工具了,虽然有一些地方和ObjC比起来要“落后”一些,但也无伤大雅.这里就用Xcode6 Beta4+iOS SDK 8.0开发 ...

  9. Swift 标签控制器(tabbar添加提醒和控制器)

    // Override point for customization after application launch. //初始化window, 大小为设备物理大小 self.window = U ...

随机推荐

  1. CleanMyMac 1.10.8

    CleanMyMac是一个系统清理工具,删除系统缓存文件 , 多余的应用程序语言包 , PowerPc软件运行库等. 是个给你的硬盘瘦身的好工具 下载地址:http://soft.macx.cn/so ...

  2. 给未来的你——李开复2011级大学新生演讲

    2011年09月26日08:30 来源:<中国青年报> <中国青年报>的读者朋友们: 你们肩负着中华的未来,你们身上正涌动着创新的血脉! 无论你在哪所学校,哪个城市,你都是与众 ...

  3. c语言学习

    #include <stdio.h>void sum_diff(int *n1,int *n2,int *sum,int *diff){ *sum=*n1+*n2; *diff=(*n1& ...

  4. Linux基础命令(三)

    一.常用命令—文件目录类命令 1.ls 列出指定或默认目录的文件信息 使用形式: ls [选项] [目录名] 实例: $ls $ls –als $ls /home/sq/Desktop $ls ./D ...

  5. JLabel跟label

  6. MongoDB 2.6.x 的安装部署

    1. 下载mongodb 2.6.x版本的zip包,在D盘创建目录MongoDB,解压缩到D:\MongoDB目录. 创建数据库目录D:\MongoDB\data,接下来打开命令行窗口,切换到D:\M ...

  7. Dojo Widget中的全局变量

    转自http://blog.163.com/mqsy_yj/blog/static/2940499220121014115338929/ 前期设计了一个清除widget的功能,虽然可以从html文件中 ...

  8. 我也来学着写写WINDOWS服务-解析xml抓取数据并插入数据库

    项目告一段落,快到一年时间开发了两个系统,一个客户已经在试用,一个进入客户测试阶段,中间突然被项目经理(更喜欢叫他W工)分派一个每隔两小时用windows服务去抓取客户提供的外网xml,解析该xml, ...

  9. [Twisted] Test

    由于Twisted程序采用事件驱动,并使用Deferred来处理事件,使用Python unittest的写测试并不容易.因此, Twisted拓展了unitest,并使用命令行工具来运行测试.这些组 ...

  10. Implicit conversion from enumeration type 'enum CGImageAlphaInfo' to different enumeration type 'CGB

    Implicit conversion from enumeration type 'enum CGImageAlphaInfo' to different enumeration type 'CGB ...