diff --git a/JSBadgeView/JSBadgeView.h b/JSBadgeView/JSBadgeView.h index 1ac6595..49edfc9 100644 --- a/JSBadgeView/JSBadgeView.h +++ b/JSBadgeView/JSBadgeView.h @@ -52,33 +52,43 @@ typedef NS_ENUM(NSUInteger, JSBadgeViewAlignment) @property (nonatomic, strong) UIColor *badgeBackgroundColor UI_APPEARANCE_SELECTOR; /** - * @discussion color of the overlay circle at the top. Default is semi-transparent white. + * Color of the overlay circle at the top. Default is semi-transparent white. */ @property (nonatomic, strong) UIColor *badgeOverlayColor UI_APPEARANCE_SELECTOR; /** - * @discussion color of the badge shadow. Default is semi-transparent black. + * Color of the badge shadow. Default is semi-transparent black. */ @property (nonatomic, strong) UIColor *badgeShadowColor UI_APPEARANCE_SELECTOR; /** - * @discussion color of the circle around the badge. Default is white. + * Offset of the badge shadow. Default is 3.0 points down. + */ +@property (nonatomic, assign) CGSize badgeShadowSize UI_APPEARANCE_SELECTOR; + +/** + * Width of the circle around the badge. Default is 2.0 points. + */ +@property (nonatomic, assign) CGFloat badgeStrokeWidth UI_APPEARANCE_SELECTOR; + +/** + * Color of the circle around the badge. Default is white. */ @property (nonatomic, strong) UIColor *badgeStrokeColor UI_APPEARANCE_SELECTOR; /** - * @discussion allows to shift the badge by x and y points. + * Allows to shift the badge by x and y points. */ @property (nonatomic, assign) CGPoint badgePositionAdjustment UI_APPEARANCE_SELECTOR; /** - * @discussion (optional) If not provided, the superview frame is used. * You can use this to position the view if you're drawing it using drawRect instead of `-addSubview:` + * (optional) If not provided, the superview frame is used. */ @property (nonatomic, assign) CGRect frameToPositionInRelationWith UI_APPEARANCE_SELECTOR; /** - * @discussion optionally init using this method to have the badge automatically added to another view. + * Optionally init using this method to have the badge automatically added to another view. */ - (id)initWithParentView:(UIView *)parentView alignment:(JSBadgeViewAlignment)alignment; diff --git a/JSBadgeView/JSBadgeView.m b/JSBadgeView/JSBadgeView.m index 7b3807d..96cbee9 100644 --- a/JSBadgeView/JSBadgeView.m +++ b/JSBadgeView/JSBadgeView.m @@ -28,48 +28,90 @@ of this software and associated documentation files (the "Software"), to deal #error JSBadgeView must be compiled with ARC. #endif -#define kDefaultBadgeTextColor [UIColor whiteColor] -#define kDefaultBadgeBackgroundColor [UIColor redColor] -#define kDefaultOverlayColor [UIColor colorWithWhite:1.0f alpha:0.3] +static const CGFloat JSBadgeViewShadowRadius = 1.0f; +static const CGFloat JSBadgeViewHeight = 16.0f; +static const CGFloat JSBadgeViewTextSideMargin = 8.0f; +static const CGFloat JSBadgeViewCornerRadius = 10.0f; -#define kDefaultBadgeTextFont [UIFont boldSystemFontOfSize:[UIFont systemFontSize]] - -#define kDefaultBadgeShadowColor [UIColor clearColor] - -#define kDefaultBadgeStrokeColor [UIColor whiteColor] -#define kBadgeStrokeWidth 2.0f +// Thanks to Peter Steinberger: https://gist.github.com/steipete/6526860 +static BOOL JSBadgeViewIsUIKitFlatMode(void) +{ + static BOOL isUIKitFlatMode = NO; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ +#ifndef kCFCoreFoundationVersionNumber_iOS_7_0 +#define kCFCoreFoundationVersionNumber_iOS_7_0 847.2 +#endif -#define kMarginToDrawInside (kBadgeStrokeWidth * 2) + if (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_7_0) + { + // If your app is running in legacy mode, tintColor will be nil - else it must be set to some color. + if (UIApplication.sharedApplication.keyWindow) + { + isUIKitFlatMode = [UIApplication.sharedApplication.keyWindow performSelector:@selector(tintColor)] != nil; + } + else + { + // Possible that we're called early on (e.g. when used in a Storyboard). Adapt and use a temporary window. + isUIKitFlatMode = [[[UIWindow alloc] init] performSelector:@selector(tintColor)] != nil; + } + } + }); -#define kShadowOffset CGSizeMake(0.0f, 3.0f) -#define kShadowOpacity 0.4f -#define kDefaultShadowColor [UIColor colorWithWhite:0.0f alpha:kShadowOpacity] -#define kShadowRadius 1.0f + return isUIKitFlatMode; +} -#define kBadgeHeight 16.0f -#define kBadgeTextSideMargin 8.0f +@implementation JSBadgeView -#define kBadgeCornerRadius 10.0f ++ (void)applyCommonStyle +{ + JSBadgeView *badgeViewAppearanceProxy = JSBadgeView.appearance; -#define kDefaultBadgeAlignment JSBadgeViewAlignmentTopRight + badgeViewAppearanceProxy.backgroundColor = UIColor.clearColor; + badgeViewAppearanceProxy.badgeAlignment = JSBadgeViewAlignmentTopRight; + badgeViewAppearanceProxy.badgeBackgroundColor = UIColor.redColor; + badgeViewAppearanceProxy.badgeTextFont = [UIFont boldSystemFontOfSize:UIFont.systemFontSize]; + badgeViewAppearanceProxy.badgeTextColor = UIColor.whiteColor; +} -@implementation JSBadgeView ++ (void)applyLegacyStyle +{ + JSBadgeView *badgeViewAppearanceProxy = JSBadgeView.appearance; + + badgeViewAppearanceProxy.badgeOverlayColor = [UIColor colorWithWhite:1.0f alpha:0.3]; + badgeViewAppearanceProxy.badgeTextShadowColor = UIColor.clearColor; + badgeViewAppearanceProxy.badgeShadowColor = [UIColor colorWithWhite:0.0f alpha:0.4f]; + badgeViewAppearanceProxy.badgeShadowSize = CGSizeMake(0.0f, 3.0f); + badgeViewAppearanceProxy.badgeStrokeWidth = 2.0f; + badgeViewAppearanceProxy.badgeStrokeColor = UIColor.whiteColor; +} -- (void)awakeFromNib ++ (void)applyIOS7Style { - [super awakeFromNib]; + JSBadgeView *badgeViewAppearanceProxy = JSBadgeView.appearance; - [self _init]; + badgeViewAppearanceProxy.badgeOverlayColor = UIColor.clearColor; + badgeViewAppearanceProxy.badgeTextShadowColor = UIColor.clearColor; + badgeViewAppearanceProxy.badgeShadowColor = UIColor.clearColor; + badgeViewAppearanceProxy.badgeStrokeWidth = 0.0f; + badgeViewAppearanceProxy.badgeStrokeColor = badgeViewAppearanceProxy.badgeBackgroundColor; } -- (id)initWithFrame:(CGRect)frame ++ (void)initialize { - if ((self = [super initWithFrame:frame])) + if (self == JSBadgeView.class) { - [self _init]; - } + [self applyCommonStyle]; - return self; + if (JSBadgeViewIsUIKitFlatMode()) + { + [self applyIOS7Style]; + } + else + { + [self applyLegacyStyle]; + } + } } - (id)initWithParentView:(UIView *)parentView alignment:(JSBadgeViewAlignment)alignment @@ -83,23 +125,13 @@ - (id)initWithParentView:(UIView *)parentView alignment:(JSBadgeViewAlignment)al return self; } -- (void)_init -{ - self.backgroundColor = [UIColor clearColor]; - - _badgeAlignment = kDefaultBadgeAlignment; - - _badgeBackgroundColor = kDefaultBadgeBackgroundColor; - _badgeOverlayColor = kDefaultOverlayColor; - _badgeTextColor = kDefaultBadgeTextColor; - _badgeTextShadowColor = kDefaultBadgeShadowColor; - _badgeTextFont = kDefaultBadgeTextFont; - _badgeShadowColor = kDefaultBadgeShadowColor; - _badgeStrokeColor = kDefaultBadgeStrokeColor; -} - #pragma mark - Layout +- (CGFloat)marginToDrawInside +{ + return self.badgeStrokeWidth * 2.0f; +} + - (void)layoutSubviews { [super layoutSubviews]; @@ -108,9 +140,10 @@ - (void)layoutSubviews const CGRect superviewBounds = CGRectIsEmpty(_frameToPositionInRelationWith) ? self.superview.bounds : _frameToPositionInRelationWith; const CGFloat textWidth = [self sizeOfTextForCurrentSettings].width; - - const CGFloat viewWidth = textWidth + kBadgeTextSideMargin + (kMarginToDrawInside * 2); - const CGFloat viewHeight = kBadgeHeight + (kMarginToDrawInside * 2); + + const CGFloat marginToDrawInside = [self marginToDrawInside]; + const CGFloat viewWidth = textWidth + JSBadgeViewTextSideMargin + (marginToDrawInside * 2); + const CGFloat viewHeight = JSBadgeViewHeight + (marginToDrawInside * 2); const CGFloat superviewWidth = superviewBounds.size.width; const CGFloat superviewHeight = superviewBounds.size.height; @@ -250,6 +283,17 @@ - (void)setBadgeBackgroundColor:(UIColor *)badgeBackgroundColor } } +- (void)setBadgeStrokeWidth:(CGFloat)badgeStrokeWidth +{ + if (badgeStrokeWidth != _badgeStrokeWidth) + { + _badgeStrokeWidth = badgeStrokeWidth; + + [self setNeedsLayout]; + [self setNeedsDisplay]; + } +} + - (void)setBadgeStrokeColor:(UIColor *)badgeStrokeColor { if (badgeStrokeColor != _badgeStrokeColor) @@ -270,6 +314,16 @@ - (void)setBadgeShadowColor:(UIColor *)badgeShadowColor } } +- (void)setBadgeShadowSize:(CGSize)badgeShadowSize +{ + if (!CGSizeEqualToSize(badgeShadowSize, _badgeShadowSize)) + { + _badgeShadowSize = badgeShadowSize; + + [self setNeedsDisplay]; + } +} + #pragma mark - Drawing - (void)drawRect:(CGRect)rect @@ -279,10 +333,11 @@ - (void)drawRect:(CGRect)rect if (anyTextToDraw) { CGContextRef ctx = UIGraphicsGetCurrentContext(); + + const CGFloat marginToDrawInside = [self marginToDrawInside]; + const CGRect rectToDraw = CGRectInset(rect, marginToDrawInside, marginToDrawInside); - const CGRect rectToDraw = CGRectInset(rect, kMarginToDrawInside, kMarginToDrawInside); - - UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:rectToDraw byRoundingCorners:(UIRectCorner)UIRectCornerAllCorners cornerRadii:CGSizeMake(kBadgeCornerRadius, kBadgeCornerRadius)]; + UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:rectToDraw byRoundingCorners:(UIRectCorner)UIRectCornerAllCorners cornerRadii:CGSizeMake(JSBadgeViewCornerRadius, JSBadgeViewCornerRadius)]; /* Background and shadow */ CGContextSaveGState(ctx); @@ -290,7 +345,7 @@ - (void)drawRect:(CGRect)rect CGContextAddPath(ctx, borderPath.CGPath); CGContextSetFillColorWithColor(ctx, self.badgeBackgroundColor.CGColor); - CGContextSetShadowWithColor(ctx, kShadowOffset, kShadowRadius, self.badgeShadowColor.CGColor); + CGContextSetShadowWithColor(ctx, self.badgeShadowSize, JSBadgeViewShadowRadius, self.badgeShadowColor.CGColor); CGContextDrawPath(ctx, kCGPathFill); } @@ -327,7 +382,7 @@ - (void)drawRect:(CGRect)rect { CGContextAddPath(ctx, borderPath.CGPath); - CGContextSetLineWidth(ctx, kBadgeStrokeWidth); + CGContextSetLineWidth(ctx, self.badgeStrokeWidth); CGContextSetStrokeColorWithColor(ctx, self.badgeStrokeColor.CGColor); CGContextDrawPath(ctx, kCGPathStroke); diff --git a/README.md b/README.md index 8df3b9e..810c9a1 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ Very optimized for performance: drawn entirely using CoreGraphics. +iOS 7 style: + + + ## Usage - Clone the repository: @@ -30,14 +34,14 @@ badgeView.badgeText = @"3"; - Check the header file for all the things you can customize. ## [CocoaPods](http://cocoapods.org/): -- Add `pod 'JSBadgeView', '~> 1.2.0'` to your `Podfile`. +- Add `pod 'JSBadgeView', '~> 1.3.0'` to your `Podfile`. - You're done! ## `UIAppearance` - You can customize all `JSBadgeView`s in your application, or the ones that are subviews of a specific type of view, using `UIAppearance`. Example: ```objc -[[JSBadgeView appearance] setBadgeBackgroundColor:[UIColor blackColor]]; +[[JSBadgeView appearance] setBadgeBackgroundColor:UIColor.blackColor]; [[JSBadgeView appearance] setBadgeAlignment:@(JSBadgeViewAlignmentTopRight)]; ```