补充

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

ios不显示vconsole_ios不显示vconsole

简单测试了一下,确实有这个问题,因为我本人项目是将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上:

ios不显示vconsole_控件_02

图层如下:

ios不显示vconsole_ios不显示vconsole_03

正文

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

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

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

ios不显示vconsole_赋值_04

方法有很多,比如:写个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赋值即可,效果如下:

ios不显示vconsole_ios不显示vconsole_05

于是我在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]; //"我的"移除红点

分享完毕。