zoukankan      html  css  js  c++  java
  • 为你的TabBar添加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
    著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 相关阅读:
    LeetCode Count of Range Sum
    LeetCode 158. Read N Characters Given Read4 II
    LeetCode 157. Read N Characters Given Read4
    LeetCode 317. Shortest Distance from All Buildings
    LeetCode Smallest Rectangle Enclosing Black Pixels
    LeetCode 315. Count of Smaller Numbers After Self
    LeetCode 332. Reconstruct Itinerary
    LeetCode 310. Minimum Height Trees
    LeetCode 163. Missing Ranges
    LeetCode Verify Preorder Serialization of a Binary Tree
  • 原文地址:https://www.cnblogs.com/isItOk/p/5709334.html
Copyright © 2011-2022 走看看