[iOS]UIButton+Badge

mac2025-08-08  14

Demo:https://download.csdn.net/download/u012881779/11950106 项目中看到大佬写的UIButton+Badge非常不错,这里写个demo修复了一些bug后分享下. 示意图:

#import "InfoViewController.h" #import "UIButton+Badge.h" @interface InfoViewController () @property (weak, nonatomic) IBOutlet UIButton *homeBut; @property (assign, nonatomic) NSInteger num; @end @implementation InfoViewController - (void)viewDidLoad { [super viewDidLoad]; } // 点击 加|减 按钮 - (IBAction)tapAddOrSubAction:(id)sender { UIButton *tempBut = (UIButton *)sender; if (tempBut.tag == 2100) { // 减 _num = _num - 1; if (_num < 0) { _num = 0; } } else if (tempBut.tag == 2101) { // 加 _num = _num + 1; } [_homeBut setBadgeValue:[NSString stringWithFormat:@"%ld",(long)_num]]; [self setupBadgeWithButton:_homeBut]; } // 设置标记 必须在setBadgeValue:方法之后调用,因为要先让badge初始化. - (void)setupBadgeWithButton:(UIButton *)button { // 当角标为0时,自动去除角标 button.shouldHideBadgeAtZero = YES; // 当角标的值发生变化,角标的动画是否显示 button.shouldAnimateBadge = YES; // 角标的最小尺寸 button.badgeMinSize = 10; // 角标的x值 button.badgeOriginX = button.frame.size.width - button.badge.frame.size.width/2.0; // 角标的y值 button.badgeOriginY = -7; } @end

UIButton+Badge 因为category中不能添加属性,所以这里大佬们使用的运行时处理.

#import <UIKit/UIKit.h> NS_ASSUME_NONNULL_BEGIN @interface UIButton (Badge) @property (strong, nonatomic) UILabel *badge; /** * 角标显示的信息,可以为数字和文字 */ @property (nonatomic) NSString *badgeValue; /** * 角标背景颜色,默认为红色 */ @property (nonatomic) UIColor *badgeBGColor; /** * 角标文字的颜色 */ @property (nonatomic) UIColor *badgeTextColor; /** * 角标字号 */ @property (nonatomic) UIFont *badgeFont; /** * 角标的气泡边界 */ @property (nonatomic) CGFloat badgePadding; /** * 角标的最小尺寸 */ @property (nonatomic) CGFloat badgeMinSize; /** * 角标的x值 */ @property (nonatomic) CGFloat badgeOriginX; /** * 角标的y值 */ @property (nonatomic) CGFloat badgeOriginY; /** * 当角标为0时,自动去除角标 */ @property BOOL shouldHideBadgeAtZero; /** * 当角标的值发生变化,角标的动画是否显示 */ @property BOOL shouldAnimateBadge; @end #import "UIButton+Badge.h" #import <objc/runtime.h> NSString const *badgeKey = @"badgeKey"; NSString const *badgeBGColorKey = @"badgeBGColorKey"; NSString const *badgeTextColorKey = @"badgeTextColorKey"; NSString const *badgeFontKey = @"badgeFontKey"; NSString const *badgePaddingKey = @"badgePaddingKey"; NSString const *badgeMinSizeKey = @"badgeMinSizeKey"; NSString const *badgeOriginXKey = @"badgeOriginXKey"; NSString const *badgeOriginYKey = @"badgeOriginYKey"; NSString const *shouldHideBadgeAtZeroKey = @"shouldHideBadgeAtZeroKey"; NSString const *shouldAnimateBadgeKey = @"shouldAnimateBadgeKey"; NSString const *badgeValueKey = @"badgeValueKey"; @implementation UIButton (Badge) - (void)badgeInit { // 初始化,设定默认值 self.badgeBGColor = [UIColor redColor]; self.badgeTextColor = [UIColor whiteColor]; self.badgeFont = [UIFont systemFontOfSize:12.0]; self.badgePadding = 6; self.badgeMinSize = 8; self.badgeOriginX = self.frame.size.width - self.badge.frame.size.width/2; self.badgeOriginY = -4; self.shouldHideBadgeAtZero = YES; self.shouldAnimateBadge = YES; // 避免角标被裁剪 self.clipsToBounds = NO; } #pragma mark - Utility methods // 当角标的属性改变时,调用此方法 - (void)refreshBadge { // 更新属性 self.badge.textColor = self.badgeTextColor; self.badge.backgroundColor = self.badgeBGColor; self.badge.font = self.badgeFont; } - (CGSize)badgeExpectedSize { // 自适应角标 UILabel *frameLabel = [self duplicateLabel:self.badge]; [frameLabel sizeToFit]; CGSize expectedLabelSize = frameLabel.frame.size; return expectedLabelSize; } // 更新角标的frame - (void)updateBadgeFrame { CGSize expectedLabelSize = [self badgeExpectedSize]; CGFloat minHeight = expectedLabelSize.height; // 判断如果小于最小size,则为最小size minHeight = (minHeight < self.badgeMinSize) ? self.badgeMinSize : expectedLabelSize.height; CGFloat minWidth = expectedLabelSize.width; CGFloat padding = self.badgePadding; // 填充边界 minWidth = (minWidth < minHeight) ? minHeight : expectedLabelSize.width; self.badge.frame = CGRectMake(self.badgeOriginX, self.badgeOriginY, minWidth + padding, minHeight + padding); self.badge.layer.cornerRadius = (minHeight + padding) / 2; self.badge.layer.masksToBounds = YES; } // 角标值变化 - (void)updateBadgeValueAnimated:(BOOL)animated { // 动画效果 if (animated && self.shouldAnimateBadge && ![self.badge.text isEqualToString:self.badgeValue]) { CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; [animation setFromValue:[NSNumber numberWithFloat:1.5]]; [animation setToValue:[NSNumber numberWithFloat:1]]; [animation setDuration:0.2]; [animation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:.4f :1.3f :1.f :1.f]]; [self.badge.layer addAnimation:animation forKey:@"bounceAnimation"]; } self.badge.text = self.badgeValue; // 动画时间 NSTimeInterval duration = animated ? 0.2 : 0; [UIView animateWithDuration:duration animations:^{ [self updateBadgeFrame]; }]; } - (UILabel *)duplicateLabel:(UILabel *)labelToCopy { UILabel *duplicateLabel = [[UILabel alloc] initWithFrame:labelToCopy.frame]; duplicateLabel.text = labelToCopy.text; duplicateLabel.font = labelToCopy.font; return duplicateLabel; } - (void)removeBadge { // 移除角标 [UIView animateWithDuration:0.2 animations:^{ // 这句代码报错 [Unknown process name] CGAffineTransformInvert: singular matrix. //self.badge.transform = CGAffineTransformMakeScale(0, 0); } completion:^(BOOL finished) { [self.badge removeFromSuperview]; }]; } #pragma mark - getters/setters - (UILabel *)badge { return objc_getAssociatedObject(self, &badgeKey); } - (void)setBadge:(UILabel *)badgeLabel { objc_setAssociatedObject(self, &badgeKey, badgeLabel, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } // 显示角标 - (NSString *)badgeValue { return objc_getAssociatedObject(self, &badgeValueKey); } - (void)setBadgeValue:(NSString *)badgeValue { objc_setAssociatedObject(self, &badgeValueKey, badgeValue, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // 当角标信息不存在,或者为空,则移除 if (!badgeValue || [badgeValue isEqualToString:@""] || [badgeValue isEqualToString:@"0"]) { [self removeBadge]; } else if (!self.badge) { // 当又有值时,重新设置角标 self.badge = [[UILabel alloc] initWithFrame:CGRectMake(self.badgeOriginX, self.badgeOriginY, 20, 20)]; self.badge.textColor = self.badgeTextColor; self.badge.backgroundColor = self.badgeBGColor; self.badge.font = self.badgeFont; self.badge.textAlignment = NSTextAlignmentCenter; [self badgeInit]; [self addSubview:self.badge]; [self updateBadgeValueAnimated:NO]; } else { [self addSubview:self.badge]; [self updateBadgeValueAnimated:YES]; } } // 进行关联 - (UIColor *)badgeBGColor { return objc_getAssociatedObject(self, &badgeBGColorKey); } // 获取关联 - (void)setBadgeBGColor:(UIColor *)badgeBGColor { objc_setAssociatedObject(self, &badgeBGColorKey, badgeBGColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (self.badge) { [self refreshBadge]; } } - (UIColor *) badgeTextColor { return objc_getAssociatedObject(self, &badgeTextColorKey); } - (void)setBadgeTextColor:(UIColor *)badgeTextColor { objc_setAssociatedObject(self, &badgeTextColorKey, badgeTextColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (self.badge) { [self refreshBadge]; } } - (UIFont *)badgeFont { return objc_getAssociatedObject(self, &badgeFontKey); } -(void)setBadgeFont:(UIFont *)badgeFont { objc_setAssociatedObject(self, &badgeFontKey, badgeFont, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (self.badge) { [self refreshBadge]; } } - (CGFloat)badgePadding { NSNumber *number = objc_getAssociatedObject(self, &badgePaddingKey); return number.floatValue; } - (void)setBadgePadding:(CGFloat)badgePadding { NSNumber *number = [NSNumber numberWithDouble:badgePadding]; objc_setAssociatedObject(self, &badgePaddingKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (self.badge) { [self updateBadgeFrame]; } } - (CGFloat)badgeMinSize { NSNumber *number = objc_getAssociatedObject(self, &badgeMinSizeKey); return number.floatValue; } - (void)setBadgeMinSize:(CGFloat)badgeMinSize { NSNumber *number = [NSNumber numberWithDouble:badgeMinSize]; objc_setAssociatedObject(self, &badgeMinSizeKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (self.badge) { [self updateBadgeFrame]; } } - (CGFloat)badgeOriginX { NSNumber *number = objc_getAssociatedObject(self, &badgeOriginXKey); return number.floatValue; } - (void)setBadgeOriginX:(CGFloat)badgeOriginX { NSNumber *number = [NSNumber numberWithDouble:badgeOriginX]; objc_setAssociatedObject(self, &badgeOriginXKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (self.badge) { [self updateBadgeFrame]; } } - (CGFloat)badgeOriginY { NSNumber *number = objc_getAssociatedObject(self, &badgeOriginYKey); return number.floatValue; } - (void)setBadgeOriginY:(CGFloat)badgeOriginY { NSNumber *number = [NSNumber numberWithDouble:badgeOriginY]; objc_setAssociatedObject(self, &badgeOriginYKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC); if (self.badge) { [self updateBadgeFrame]; } } - (BOOL)shouldHideBadgeAtZero { NSNumber *number = objc_getAssociatedObject(self, &shouldHideBadgeAtZeroKey); return number.boolValue; } - (void)setShouldHideBadgeAtZero:(BOOL)shouldHideBadgeAtZero { NSNumber *number = [NSNumber numberWithBool:shouldHideBadgeAtZero]; objc_setAssociatedObject(self, &shouldHideBadgeAtZeroKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (BOOL)shouldAnimateBadge { NSNumber *number = objc_getAssociatedObject(self, &shouldAnimateBadgeKey); return number.boolValue; } - (void)setShouldAnimateBadge:(BOOL)shouldAnimateBadge { NSNumber *number = [NSNumber numberWithBool:shouldAnimateBadge]; objc_setAssociatedObject(self, &shouldAnimateBadgeKey, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } @end

 

最新回复(0)