UIView+RedPoint实现底部UITabBarItem和控件的右上角显示和隐藏红点/数字的需求

补充

前两天有个读者告诉我,UIButton进行了圆角切割之后红点和数字无法正常显示:
图片描述

简单测试了一下,确实有这个问题,因为我本人项目是将Image绘制成圆形,所以没有发现这个问题,一般不直接对控件进行处理。

两种简单的解决方法:

1.不切割控件,将Image绘制成需要的圆形:

//图像圆角切割
- (UIImage *)ymtGetCornerRadius:(CGFloat)cornerRadius {
    CGFloat scale = [UIScreen mainScreen].scale;
    UIGraphicsBeginImageContextWithOptions(self.size, NO, scale);
    CGContextRef c = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius];
    CGContextAddPath(c, path.CGPath);
    CGContextClip(c);
    [self drawInRect:rect];
    CGContextDrawPath(c, kCGPathFillStroke);
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

2.在button外面套一个空白的view,红点显示在view上:
图片描述

图层如下:
图片描述

正文

相信很多开发者遇到过按钮或图片右上角需要显示红点/数字的需求。

普通图片/按钮/Label右上角显示红点或数字

前段时间,公司项目加入了新闻资讯功能,要求收到普通新闻在新闻logo右上角显示红点,重磅消息在logo右上角显示收到的重磅消息的数量,效果如下图:

图片描述

方法有很多,比如:写个Label加入cell中放在图片右上角、切换图片等等,本文使用Category对Class进行扩展的方法实现该需求,适用于各种view。

先上代码。

UIView+redPoint.h文件代码如下,分别给出show方法和hide方法:

//
//  UIView+redPoint.h
//  Medicine
//
//  Created by zhujiamin on 16/4/16.
//  Copyright © 2016年 MedEx. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface UIView (redPoint)

- (void)showRedAtOffSetX:(float)offsetX AndOffSetY:(float)offsetY OrValue:(NSString *)value;
- (void)hideRedPoint;

@end

UIView+redPoint.m文件中具体方法实现如下:

#pragma other(redPoint)
//添加显示
- (void)showRedAtOffSetX:(float)offsetX AndOffSetY:(float)offsetY OrValue:(NSString *)value{
    [self removeRedPoint];//添加之前先移除,避免重复添加
    //新建小红点
    UIView *badgeView = [[UIView alloc]init];
    badgeView.tag = 998;
    
    CGFloat viewWidth = 12;
    if (value) {
        viewWidth = 18;
        UILabel *valueLbl = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, viewWidth, viewWidth)];
        valueLbl.text = value;
        valueLbl.font = FONT_12;
        valueLbl.textColor = [UIColor whiteColor];
        valueLbl.textAlignment = NSTextAlignmentCenter;
        valueLbl.clipsToBounds = YES;
        [badgeView addSubview:valueLbl];
    }
   
    badgeView.layer.cornerRadius = viewWidth / 2;
    badgeView.backgroundColor = [UIColor redColor];
    CGRect tabFrame = self.frame;
    
    //确定小红点的位置
    if (offsetX == 0) {
        offsetX = 1;
    }
    
    if (offsetY == 0) {
        offsetY = 0.05;
    }
    CGFloat x = ceilf(tabFrame.size.width + offsetX);
    CGFloat y = ceilf(offsetY * tabFrame.size.height);
    
    badgeView.frame = CGRectMake(x, y, viewWidth, viewWidth);
    [self addSubview:badgeView];
}

//隐藏
- (void)hideRedPoint{
    [self removeRedPoint];
}

//移除
- (void)removeRedPoint{
    //按照tag值进行移除
    for (UIView *subView in self.subviews) {
        if (subView.tag == 998) {
            [subView removeFromSuperview];
        }
    }
}

为了满足不同位置的显示

- (void)showRedAtOffSetX:(float)offsetX AndOffSetY:(float)offsetY OrValue:(NSString *)value;

此方法接收调用时给入想要显示的红点或者数字相对父view的最大X值的偏移,和高度的倍数;

if (offsetX == 0) {
    offsetX = 1;
}
    
if (offsetY == 0) {
    offsetY = 0.05; 
}
CGFloat x = ceilf(tabFrame.size.width + offsetX);
CGFloat y = ceilf(offsetY * tabFrame.size.height);

默认需要显示在右上角时,offsetX和offsetY可以设置为0,根据具体需求给出不同的数值即可;
本例需要Button右上角显示红点,需要显示红点时Value值赋为nil,若需显示数字则赋值相应的字符即可,调用方法如下:

[centerBtn showRedAtOffSetX:0 AndOffSetY:0 OrValue:nil];

[centerBtn showRedAtOffSetX:0 AndOffSetY:0 OrValue:@"2"];

需要隐藏红点/数字时只需要调用

[sender hideRedPoint];

方法将其移除即可。

底部TabbarItem右上角显示红点或数字

实现这个需求的时候,我想到先前做的底部tabbar下的item显示红点的方法,使用的是粗暴的切换图片方法,实际上UITabbar也继承于UIView,这种思路同样适用,不过tabbar只需要显示和隐藏红点即可,显示数字使用系统的badgeValue赋值即可,效果如下:

图片描述

于是我在UIView+redPoint.h文件中加入了以下两个方法供UITabbar调用,index参数为要显示红点的item的序号。

//tabbar方法
- (void)showBadgeOnItemIndex:(int)index; //显示小红点
- (void)hideBadgeOnItemIndex:(int)index; //隐藏小红点

具体实现方法和前面讲到的其他控件显示方法类似,只不过要准确计算显示红点的位置,具体实现如下:

#define USERDEF     [NSUserDefaults standardUserDefaults] //宏定义NSUserDefaults用来存本地标记
#pragma mark Tabbar(redPoint)
//显示小红点
- (void)showBadgeOnItemIndex:(int)index{
    NSString *keyStr = [NSString stringWithFormat:@"%d_HADSET",index];
    if ([USERDEF objectForKey:keyStr]) {
        return;
    } else {
        [USERDEF setObject:@"HADSET" forKey:keyStr];
    }
    //移除之前可能存在的小红点
    [self removeBadgeOnItemIndex:index];
    
    //新建小红点
    UIView *badgeView = [[UIView alloc]init];
    badgeView.tag = 888 + index;
    badgeView.layer.cornerRadius = 6;
    badgeView.backgroundColor = [UIColor redColor];
    CGRect tabFrame = self.frame;
    
    //确定小红点的位置
    float percentX = (index +0.55) / 5; //5为tabbaritem的总个数
    CGFloat x = ceilf(percentX * tabFrame.size.width);
    CGFloat y = ceilf(0.05 * tabFrame.size.height);
    badgeView.frame = CGRectMake(x, y, 12, 12);
    
    [self addSubview:badgeView];
}

//隐藏小红点
- (void)hideBadgeOnItemIndex:(int)index{
    NSString *keyStr = [NSString stringWithFormat:@"%d_HADSET",index];
    //移除小红点
    [self removeBadgeOnItemIndex:index];
    if ([USERDEF objectForKey:keyStr]) {
        [USERDEF removeObjectForKey:keyStr];
    }
}

//移除
- (void)removeBadgeOnItemIndex:(int)index{
    //按照tag值进行移除
    for (UIView *subView in self.subviews) {
        if (subView.tag == 888+index) {
            [subView removeFromSuperview];
        }
    }
}

因为tabar红点设置方法调用比较频繁,为了避免每次重复移除重设操作,我在红点show成功之后会对当前item进行本地标记,每次调用showBadgeOnItemIndex:方法会先判断当前index是否已经显示红点,已经显示则不在重复设置,调用hideBadgeOnItemIndex:方法时,移除该标记。

NSString *keyStr = [NSString stringWithFormat:@"%d_HADSET",index];
if ([USERDEF objectForKey:keyStr]) {
    return;
} else {
    [USERDEF setObject:@"HADSET" forKey:keyStr];
}
NSString *keyStr = [NSString stringWithFormat:@"%d_HADSET",index];
if ([USERDEF objectForKey:keyStr]) {
    [USERDEF removeObjectForKey:keyStr];
}

显示/隐藏调用方法如下:

[self.tabBarController.tabBar showBadgeOnItemIndex:4]; //"我的"显示红点
[self.tabBarController.tabBar hideBadgeOnItemIndex:4]; //"我的"移除红点

分享完毕。

本人坐标杭州,后续我会陆续把工作中遇到的问题及解决方案分享出来,互相交流学习,本人QQ:815187811,欢迎结交[笑脸].


iOS实用技巧
享受分享之美

iOS进阶中

121 声望
20 粉丝
0 条评论
推荐阅读
CocoaPods创建公有和私有Pod库方法总结
刚毕业那段时间接触到的一些文章到处都在大谈iOS工程模块化(CocoaPods化), 本人也一直在着力于将公司项目代码解耦合, 但是因为一个人开发实在没有必要将工程CocoaPods化, 所以迟迟没有去研究将工程CocoaPods化的...

佳敏_朱9阅读 27.5k评论 1

iOS 健康共享失败如何解决
您要开始与之共享的对象必须已经连同他们的 iCloud 账户邮箱一起保存在您的“通讯录”中(iCloud 账户邮箱即 iCloud 账户绑定的邮箱信息,不是强制要求 @iCloud.com 邮箱)。

岚哲阅读 5.2k

探究 iOS 内存问题
本文从 Tagged Pointer、objc 源码、dealloc 原理、AutoreleasePool 原理、野指针探究等技术点展开聊了聊 iOS 内存相关问题。

杭城小刘1阅读 1.5k

封面图
iOS IDA逆向之patch
这里介绍的是ida的patch.1.搜索svc #0x80,回到IDA View-A界面,才能正确搜索点击图中T字按钮,弹出搜索框点击列表中进入2.修改svc #0x80,在IDA View-A界面中选中svc那一行,点击工具栏Edit--&gt;Patch program--&gt...

宋冬野阅读 2k

社交场景下iOS消息流交互层实践
一款社交产品的诞生,离不开即时通讯(IM)场景。随着团队业务版图在社交领域的布局,诞生了多个社交场景APP,涉及的IM场景,包含私聊、群聊、聊天室等。

云音乐技术团队1阅读 462

封面图
SegmentFault 思否技术周刊 Vol.77 — 探究关于 iOS 的特性
本文从 Tagged Pointer、objc 源码、dealloc 原理、AutoreleasePool 原理、野指针探究等技术点展开聊了聊 iOS 内存相关问题。

Beverly阅读 1.4k

封面图
魔方带壳截图:让你的截图看起来更加高大上
我们在日常工作和生活中,往往需要截图去做汇报或分享。普通人的做法:手机或电脑截图,然后就拿去汇报或分享。这样你的截图显得平平无奇,没有给人眼前一亮的感觉。但是,如果我们给这张截图穿上一件“衣服”,把...

老人羽海阅读 1.2k

封面图

iOS进阶中

121 声望
20 粉丝
宣传栏