From 7f66659b3df05d59747eb96ebcbdaf53534be0cc Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Tue, 10 May 2016 11:39:31 +0930 Subject: [PATCH 1/5] Add support for text values --- UIView+MGBadgeView.h | 2 ++ UIView+MGBadgeView.m | 39 ++++++++++++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/UIView+MGBadgeView.h b/UIView+MGBadgeView.h index 09b1049..270aa4f 100644 --- a/UIView+MGBadgeView.h +++ b/UIView+MGBadgeView.h @@ -26,6 +26,8 @@ typedef NS_ENUM(NSUInteger, MGBadgePosition) { @property (nonatomic) NSInteger badgeValue; +@property (copy, nonatomic) NSString *badgeText; + @property(strong, nonatomic) UIFont *font; @property(strong, nonatomic) UIColor *badgeColor; diff --git a/UIView+MGBadgeView.m b/UIView+MGBadgeView.m index 2bd6e66..23b67f6 100644 --- a/UIView+MGBadgeView.m +++ b/UIView+MGBadgeView.m @@ -9,6 +9,10 @@ #import "UIView+MGBadgeView.h" #import +@interface MGBadgeView () +@property (nonatomic) BOOL useText; +@end + @implementation MGBadgeView static float const kMGBadgeViewInnerSpaceFromBorder = 7.0; @@ -43,9 +47,9 @@ - (instancetype)initWithFrame:(CGRect)frame { - (void)drawRect:(CGRect)rect { - if(_badgeValue != 0 || _displayIfZero) { + if ((_useText && (_badgeText ?: @"").length > 0) || (!_useText && (_badgeValue != 0 || _displayIfZero))) { - NSString *stringToDraw = [NSString stringWithFormat:@"%ld", (long)_badgeValue]; + NSString *stringToDraw = _useText ? (_badgeText ?: @"") : [NSString stringWithFormat:@"%ld", (long)_badgeValue]; CGContextRef context = UIGraphicsGetCurrentContext(); @@ -80,6 +84,8 @@ - (void)setBadgeValue:(NSInteger)badgeValue { if(_badgeValue != badgeValue) { _badgeValue = badgeValue; + _badgeText = nil; + _useText = NO; if(badgeValue != 0 || _displayIfZero) { [self mg_updateBadgeViewSize]; @@ -95,6 +101,24 @@ - (void)setBadgeValue:(NSInteger)badgeValue { } } +- (void)setBadgeText:(NSString *)badgeText { + if(![(badgeText ?: @"") isEqualToString:(_badgeText ?: @"")]) { + _badgeText = [NSString stringWithString:(badgeText ?: @"")]; + _badgeValue = 0; + _useText = YES; + + if(_badgeText.length > 0) { + [self mg_updateBadgeViewSize]; + if(_position == MGBadgePositionBest) + [self mg_updateBadgeViewPosition]; + } else { + self.frame = CGRectZero; + } + + [self setNeedsDisplay]; + } +} + - (void)setPosition:(MGBadgePosition)position { if(_position != position) { _position = position; @@ -181,10 +205,15 @@ - (void)setDisplayIfZero:(BOOL)displayIfZero { - (void)mg_updateBadgeViewSize { //Calculate badge bounds - CGSize numberSize = [[NSString stringWithFormat:@"%ld", (long)_badgeValue] sizeWithAttributes:@{NSFontAttributeName: _font}]; + CGSize contentSize = CGSizeZero; + if (_useText) { + contentSize = [(_badgeText ?: @"") sizeWithAttributes:@{NSFontAttributeName: _font}]; + } else { + contentSize = [[NSString stringWithFormat:@"%ld", (long)_badgeValue] sizeWithAttributes:@{NSFontAttributeName: _font}]; + } - float badgeHeight = MAX(BADGE_TOTAL_OFFSET + numberSize.height, _minDiameter); - float badgeWidth = MAX(badgeHeight, BADGE_TOTAL_OFFSET + numberSize.width); + float badgeHeight = MAX(BADGE_TOTAL_OFFSET + contentSize.height, _minDiameter); + float badgeWidth = MAX(badgeHeight, BADGE_TOTAL_OFFSET + contentSize.width); [self setBounds:CGRectMake(0, 0, badgeWidth, badgeHeight)]; } From ba29a0684aedfbfc5250a49d91cbd6474488d693 Mon Sep 17 00:00:00 2001 From: Shane Woolcock Date: Tue, 10 May 2016 12:00:58 +0930 Subject: [PATCH 2/5] Change ellipse to "pill" shape for long text values --- UIView+MGBadgeView.m | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/UIView+MGBadgeView.m b/UIView+MGBadgeView.m index 23b67f6..4af8f56 100644 --- a/UIView+MGBadgeView.m +++ b/UIView+MGBadgeView.m @@ -9,6 +9,19 @@ #import "UIView+MGBadgeView.h" #import +void MGFillRoundedRect(CGContextRef __nullable context, CGRect rect, CGFloat radius) { + CGFloat theRadius = MAX(radius, rect.size.height/2.0); + CGFloat minx = CGRectGetMinX(rect), midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect); + CGFloat miny = CGRectGetMinY(rect), midy = CGRectGetMidY(rect), maxy = CGRectGetMaxY(rect); + CGContextMoveToPoint(context, minx, midy); + CGContextAddArcToPoint(context, minx, miny, midx, miny, theRadius); + CGContextAddArcToPoint(context, maxx, miny, maxx, midy, theRadius); + CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, theRadius); + CGContextAddArcToPoint(context, minx, maxy, minx, midy, theRadius); + CGContextClosePath(context); + CGContextFillPath(context); +} + @interface MGBadgeView () @property (nonatomic) BOOL useText; @end @@ -54,10 +67,11 @@ - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); [_outlineColor set]; - CGContextFillEllipseInRect(context, CGRectInset(rect, 1.0, 1.0)); + + MGFillRoundedRect(context, CGRectInset(rect, 1.0, 1.0), 0); [_badgeColor set]; - CGContextFillEllipseInRect(context, CGRectInset(rect, _outlineWidth + 1.0, _outlineWidth + 1.0)); + MGFillRoundedRect(context, CGRectInset(rect, _outlineWidth + 1.0, _outlineWidth + 1.0), 0); CGSize numberSize = [stringToDraw sizeWithAttributes:@{NSFontAttributeName: _font}]; From 8054a5c7a184ea2678604c9ad00679248540a74c Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Tue, 14 Mar 2017 09:43:05 +1030 Subject: [PATCH 3/5] Add image badge support --- UIView+MGBadgeView.h | 2 ++ UIView+MGBadgeView.m | 78 +++++++++++++++++++++++++++++--------------- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/UIView+MGBadgeView.h b/UIView+MGBadgeView.h index 270aa4f..7645489 100644 --- a/UIView+MGBadgeView.h +++ b/UIView+MGBadgeView.h @@ -28,6 +28,8 @@ typedef NS_ENUM(NSUInteger, MGBadgePosition) { @property (copy, nonatomic) NSString *badgeText; +@property (strong, nonatomic) UIImage *badgeImage; + @property(strong, nonatomic) UIFont *font; @property(strong, nonatomic) UIColor *badgeColor; diff --git a/UIView+MGBadgeView.m b/UIView+MGBadgeView.m index 4af8f56..4958b17 100644 --- a/UIView+MGBadgeView.m +++ b/UIView+MGBadgeView.m @@ -22,10 +22,6 @@ void MGFillRoundedRect(CGContextRef __nullable context, CGRect rect, CGFloat rad CGContextFillPath(context); } -@interface MGBadgeView () -@property (nonatomic) BOOL useText; -@end - @implementation MGBadgeView static float const kMGBadgeViewInnerSpaceFromBorder = 7.0; @@ -59,20 +55,29 @@ - (instancetype)initWithFrame:(CGRect)frame { } - (void)drawRect:(CGRect)rect { + NSString *stringToDraw = nil; + if(_badgeImage) { + stringToDraw = nil; + } else if(_badgeText) { + stringToDraw = _badgeText; + } else if(_badgeValue != 0 || _displayIfZero) { + stringToDraw = [NSString stringWithFormat:@"%ld", (long)_badgeValue]; + } - if ((_useText && (_badgeText ?: @"").length > 0) || (!_useText && (_badgeValue != 0 || _displayIfZero))) { - - NSString *stringToDraw = _useText ? (_badgeText ?: @"") : [NSString stringWithFormat:@"%ld", (long)_badgeValue]; - - CGContextRef context = UIGraphicsGetCurrentContext(); - - [_outlineColor set]; - - MGFillRoundedRect(context, CGRectInset(rect, 1.0, 1.0), 0); - - [_badgeColor set]; - MGFillRoundedRect(context, CGRectInset(rect, _outlineWidth + 1.0, _outlineWidth + 1.0), 0); - + CGContextRef context = UIGraphicsGetCurrentContext(); + + [_outlineColor set]; + MGFillRoundedRect(context, CGRectInset(rect, 1.0, 1.0), 0); + + [_badgeColor set]; + MGFillRoundedRect(context, CGRectInset(rect, _outlineWidth + 1.0, _outlineWidth + 1.0), 0); + + if(_badgeImage) { + CGRect imageRect = CGRectMake((rect.size.width - _badgeImage.size.width)/2.0, (rect.size.height - _badgeImage.size.height)/2.0, _badgeImage.size.width, _badgeImage.size.height); + [_badgeImage drawInRect:imageRect]; + } + + if(stringToDraw) { CGSize numberSize = [stringToDraw sizeWithAttributes:@{NSFontAttributeName: _font}]; [_textColor set]; @@ -87,19 +92,16 @@ - (void)drawRect:(CGRect)rect { NSParagraphStyleAttributeName : paragrapStyle, NSForegroundColorAttributeName : _textColor }]; - } } #pragma mark - Properties accessor methods - (void)setBadgeValue:(NSInteger)badgeValue { - if(_badgeValue != badgeValue) { - _badgeValue = badgeValue; _badgeText = nil; - _useText = NO; + _badgeImage = nil; if(badgeValue != 0 || _displayIfZero) { [self mg_updateBadgeViewSize]; @@ -119,7 +121,7 @@ - (void)setBadgeText:(NSString *)badgeText { if(![(badgeText ?: @"") isEqualToString:(_badgeText ?: @"")]) { _badgeText = [NSString stringWithString:(badgeText ?: @"")]; _badgeValue = 0; - _useText = YES; + _badgeImage = nil; if(_badgeText.length > 0) { [self mg_updateBadgeViewSize]; @@ -133,6 +135,25 @@ - (void)setBadgeText:(NSString *)badgeText { } } +- (void)setBadgeImage:(UIImage *)badgeImage { + if(_badgeImage != badgeImage) { + _badgeImage = badgeImage; + _badgeText = nil; + _badgeValue = 0; + + if(badgeImage) { + [self mg_updateBadgeViewSize]; + if(_position == MGBadgePositionBest) { + [self mg_updateBadgeViewPosition]; + } + } else { + self.frame = CGRectZero; + } + + [self setNeedsDisplay]; + } +} + - (void)setPosition:(MGBadgePosition)position { if(_position != position) { _position = position; @@ -220,19 +241,22 @@ - (void)setDisplayIfZero:(BOOL)displayIfZero { - (void)mg_updateBadgeViewSize { //Calculate badge bounds CGSize contentSize = CGSizeZero; - if (_useText) { + if (_badgeImage) { + // assume images should always be rendered in a circle, hence ensure content is square for equal padding + CGFloat imageLongestSide = MAX(_badgeImage.size.width, _badgeImage.size.height); + contentSize = CGSizeMake(imageLongestSide, imageLongestSide); + } else if(_badgeText) { contentSize = [(_badgeText ?: @"") sizeWithAttributes:@{NSFontAttributeName: _font}]; } else { contentSize = [[NSString stringWithFormat:@"%ld", (long)_badgeValue] sizeWithAttributes:@{NSFontAttributeName: _font}]; } - float badgeHeight = MAX(BADGE_TOTAL_OFFSET + contentSize.height, _minDiameter); - float badgeWidth = MAX(badgeHeight, BADGE_TOTAL_OFFSET + contentSize.width); - + float badgeHeight = ceilf(MAX(BADGE_TOTAL_OFFSET + contentSize.height, _minDiameter)); + float badgeWidth = ceilf(MAX(badgeHeight, BADGE_TOTAL_OFFSET + contentSize.width)); + [self setBounds:CGRectMake(0, 0, badgeWidth, badgeHeight)]; } - - (void)mg_updateBadgeViewPosition { CGRect superviewFrame = self.superview.frame; CGSize badgeSize = self.bounds.size; From 9c309d80565c4b7527737aa6734552dfcc72ee0e Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Fri, 15 Dec 2017 14:49:01 +1030 Subject: [PATCH 4/5] Transform the badge checking logic in drawRect --- UIView+MGBadgeView.m | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/UIView+MGBadgeView.m b/UIView+MGBadgeView.m index 4958b17..71c8522 100644 --- a/UIView+MGBadgeView.m +++ b/UIView+MGBadgeView.m @@ -56,12 +56,12 @@ - (instancetype)initWithFrame:(CGRect)frame { - (void)drawRect:(CGRect)rect { NSString *stringToDraw = nil; - if(_badgeImage) { - stringToDraw = nil; - } else if(_badgeText) { - stringToDraw = _badgeText; - } else if(_badgeValue != 0 || _displayIfZero) { - stringToDraw = [NSString stringWithFormat:@"%ld", (long)_badgeValue]; + if(!_badgeImage) { + if(_badgeText) { + stringToDraw = _badgeText; + } else if(_badgeValue != 0 || _displayIfZero) { + stringToDraw = [NSString stringWithFormat:@"%ld", (long)_badgeValue]; + } } CGContextRef context = UIGraphicsGetCurrentContext(); From 69caaecd55fc725e7bf46b382dfc1e4db7658688 Mon Sep 17 00:00:00 2001 From: Ricardo Santos Date: Fri, 15 Dec 2017 15:46:41 +1030 Subject: [PATCH 5/5] Clean up checking in set badge text --- UIView+MGBadgeView.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UIView+MGBadgeView.m b/UIView+MGBadgeView.m index 71c8522..aeaceea 100644 --- a/UIView+MGBadgeView.m +++ b/UIView+MGBadgeView.m @@ -118,8 +118,8 @@ - (void)setBadgeValue:(NSInteger)badgeValue { } - (void)setBadgeText:(NSString *)badgeText { - if(![(badgeText ?: @"") isEqualToString:(_badgeText ?: @"")]) { - _badgeText = [NSString stringWithString:(badgeText ?: @"")]; + if(_badgeText != badgeText) { + _badgeText = badgeText; _badgeValue = 0; _badgeImage = nil;