123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- //
- // MKNumberBadgeView.m
- // MKNumberBadgeView
- //
- // Copyright 2009-2012 Michael F. Kamprath
- // michael@claireware.com
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- #ifndef __has_feature
- #define __has_feature(x) 0
- #endif
- #ifndef __has_extension
- #define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
- #endif
- #if __has_feature(objc_arc) && __clang_major__ >= 3
- #error "iPhoneMK is not designed to be used with ARC. Please add '-fno-objc-arc' to the compiler flags of iPhoneMK files."
- #endif // __has_feature(objc_arc)
- #import "MKNumberBadgeView.h"
- @interface MKNumberBadgeView ()
- //
- // private methods
- //
- - (void)initState;
- - (CGPathRef)newBadgePathForTextSize:(CGSize)inSize;
- @end
- @implementation MKNumberBadgeView
- @synthesize value=_value;
- @synthesize shadow;
- @synthesize shadowOffset;
- @synthesize shadowColor;
- @synthesize shine;
- @synthesize font;
- @synthesize fillColor;
- @synthesize strokeColor;
- @synthesize strokeWidth;
- @synthesize textColor;
- @synthesize alignment;
- @dynamic badgeSize;
- @synthesize pad;
- @synthesize hideWhenZero;
- @synthesize iOS7;
- - (id)initWithFrame:(CGRect)frame
- {
- if (self = [super initWithFrame:frame])
- {
- // Initialization code
-
- [self initState];
- }
- return self;
- }
- - (id)initWithCoder:(NSCoder *)decoder
- {
- if (self = [super initWithCoder:decoder])
- {
- // Initialization code
- [self initState];
- }
- return self;
- }
- #pragma mark -- private methods --
- - (void)initState;
- {
- if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1)
- self.iOS7 = YES;
-
- self.opaque = NO;
- self.pad = 2;
- self.font = self.iOS7 ? [UIFont systemFontOfSize:16] : [UIFont boldSystemFontOfSize:16];
- self.shadow = YES;
- self.shadowOffset = CGSizeMake(0, 3);
- self.shadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];
- self.shine = YES;
- self.alignment = NSTextAlignmentCenter;
- self.fillColor = [UIColor redColor];
- self.strokeColor = [UIColor whiteColor];
- self.strokeWidth = 2.0;
- self.textColor = [UIColor whiteColor];
- self.hideWhenZero = NO;
-
- self.backgroundColor = [UIColor clearColor];
- }
- - (void)dealloc
- {
- [font release];
- [fillColor release];
- [strokeColor release];
- [textColor release];
- [shadowColor release];
-
- [super dealloc];
- }
- - (void)drawRect:(CGRect)rect
- {
- CGRect viewBounds = self.bounds;
-
- CGContextRef curContext = UIGraphicsGetCurrentContext();
- NSString* numberString;
- if (self.value == 0) {
- numberString = @"";
- } else {
- numberString = [NSString stringWithFormat:@"%lu",(unsigned long)self.value];
- }
-
- CGSize numberSize = [numberString sizeWithAttributes:@{NSFontAttributeName: self.font}];
-
- CGPathRef badgePath = [self newBadgePathForTextSize:numberSize];
-
- CGRect badgeRect = CGPathGetBoundingBox(badgePath);
-
- badgeRect.origin.x = 0;
- badgeRect.origin.y = 0;
- badgeRect.size.width = ceil( badgeRect.size.width );
- badgeRect.size.height = ceil( badgeRect.size.height );
-
-
- CGContextSaveGState( curContext );
- CGContextSetLineWidth( curContext, self.strokeWidth );
- CGContextSetStrokeColorWithColor( curContext, self.strokeColor.CGColor );
- CGContextSetFillColorWithColor( curContext, self.fillColor.CGColor );
-
- // Line stroke straddles the path, so we need to account for the outer portion
- badgeRect.size.width += ceilf( self.strokeWidth / 2 );
- badgeRect.size.height += ceilf( self.strokeWidth / 2 );
-
- CGPoint ctm;
-
- switch (self.alignment)
- {
- default:
- case NSTextAlignmentCenter:
- ctm = CGPointMake( round((viewBounds.size.width - badgeRect.size.width)/2), round((viewBounds.size.height - badgeRect.size.height)/2) );
- break;
- case NSTextAlignmentLeft:
- ctm = CGPointMake( 0, round((viewBounds.size.height - badgeRect.size.height)/2) );
- break;
- case NSTextAlignmentRight:
- ctm = CGPointMake( (viewBounds.size.width - badgeRect.size.width), round((viewBounds.size.height - badgeRect.size.height)/2) );
- break;
- }
-
- CGContextTranslateCTM( curContext, ctm.x, ctm.y);
- if (self.shadow && !iOS7)
- {
- CGContextSaveGState( curContext );
- CGSize blurSize = self.shadowOffset;
-
- CGContextSetShadowWithColor( curContext, blurSize, 4, self.shadowColor.CGColor );
-
- CGContextBeginPath( curContext );
- CGContextAddPath( curContext, badgePath );
- CGContextClosePath( curContext );
-
- CGContextDrawPath( curContext, kCGPathFillStroke );
- CGContextRestoreGState(curContext);
- }
-
- CGContextBeginPath( curContext );
- CGContextAddPath( curContext, badgePath );
- CGContextClosePath( curContext );
- CGContextDrawPath( curContext, iOS7 ? kCGPathFill : kCGPathFillStroke );
- //
- // add shine to badge
- //
-
- if (self.shine && !iOS7)
- {
- CGContextBeginPath( curContext );
- CGContextAddPath( curContext, badgePath );
- CGContextClosePath( curContext );
- CGContextClip(curContext);
-
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGFloat shinyColorGradient[8] = {1, 1, 1, 0.8, 1, 1, 1, 0};
- CGFloat shinyLocationGradient[2] = {0, 1};
- CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace,
- shinyColorGradient,
- shinyLocationGradient, 2);
-
- CGContextSaveGState(curContext);
- CGContextBeginPath(curContext);
- CGContextMoveToPoint(curContext, 0, 0);
-
- CGFloat shineStartY = badgeRect.size.height*0.25;
- CGFloat shineStopY = shineStartY + badgeRect.size.height*0.4;
-
- CGContextAddLineToPoint(curContext, 0, shineStartY);
- CGContextAddCurveToPoint(curContext, 0, shineStopY,
- badgeRect.size.width, shineStopY,
- badgeRect.size.width, shineStartY);
- CGContextAddLineToPoint(curContext, badgeRect.size.width, 0);
- CGContextClosePath(curContext);
- CGContextClip(curContext);
- CGContextDrawLinearGradient(curContext, gradient,
- CGPointMake(badgeRect.size.width / 2.0, 0),
- CGPointMake(badgeRect.size.width / 2.0, shineStopY),
- kCGGradientDrawsBeforeStartLocation);
- CGContextRestoreGState(curContext);
-
- CGColorSpaceRelease(colorSpace);
- CGGradientRelease(gradient);
-
- }
- CGContextRestoreGState( curContext );
- CGPathRelease(badgePath);
-
- CGContextSaveGState( curContext );
- CGContextSetFillColorWithColor( curContext, self.textColor.CGColor );
-
- CGPoint textPt = CGPointMake( ctm.x + (badgeRect.size.width/2) - (numberSize.width / 1.75) , ctm.y + (badgeRect.size.height / 2) - (numberSize.height / 1.75));
-
- [numberString drawAtPoint:textPt withAttributes:@{NSFontAttributeName : self.font, NSForegroundColorAttributeName: self.textColor}];
- CGContextRestoreGState( curContext );
- }
- - (CGPathRef)newBadgePathForTextSize:(CGSize)inSize
- {
- CGFloat arcRadius = ceil((inSize.height+self.pad)/2.0);
-
- CGFloat badgeWidthAdjustment = inSize.width - inSize.height/2.0;
- CGFloat badgeWidth = 2.0*arcRadius;
-
- if ( badgeWidthAdjustment > 0.0 )
- {
- badgeWidth += badgeWidthAdjustment;
- }
-
-
- CGMutablePathRef badgePath = CGPathCreateMutable();
-
- CGPathMoveToPoint( badgePath, NULL, arcRadius, 0 );
- CGPathAddArc( badgePath, NULL, arcRadius, arcRadius, arcRadius, 3.0*M_PI_2, M_PI_2, YES);
- CGPathAddLineToPoint( badgePath, NULL, badgeWidth-arcRadius, 2.0*arcRadius);
- CGPathAddArc( badgePath, NULL, badgeWidth-arcRadius, arcRadius, arcRadius, M_PI_2, 3.0*M_PI_2, YES);
- CGPathAddLineToPoint( badgePath, NULL, arcRadius, 0 );
-
- return badgePath;
-
- }
- #pragma mark -- property methods --
- - (void)setValue:(NSUInteger)inValue
- {
- _value = inValue;
-
- if (self.hideWhenZero == YES && _value == 0)
- {
- self.hidden = YES;
- }
- else
- {
- self.hidden = NO;
- }
-
- [self setNeedsDisplay];
- }
- - (CGSize)badgeSize
- {
- NSString* numberString = [NSString stringWithFormat:@"%lu",(unsigned long)self.value];
-
- CGSize numberSize = [numberString sizeWithAttributes:@{NSFontAttributeName: self.font}];
-
- CGPathRef badgePath = [self newBadgePathForTextSize:numberSize];
-
- CGRect badgeRect = CGPathGetBoundingBox(badgePath);
-
- badgeRect.origin.x = 0;
- badgeRect.origin.y = 0;
- badgeRect.size.width = ceil( badgeRect.size.width );
- badgeRect.size.height = ceil( badgeRect.size.height );
-
- CGPathRelease(badgePath);
-
- return badgeRect.size;
- }
- @end
|