标签:
A CALayer subclass that draws a very simple arrow
1 #import <QuartzCore/QuartzCore.h> 2 3 @interface ArrowLayer : CALayer 4 5 @property (nonatomic) CGFloat thickness; 6 @property (nonatomic) CGFloat startRadians; 7 @property (nonatomic) CGFloat lengthRadians; 8 @property (nonatomic) CGFloat headLengthRadians; 9 10 @property (nonatomic, strong) UIColor *fillColor; 11 @property (nonatomic, strong) UIColor *strokeColor; 12 @property (nonatomic) CGFloat lineWidth; 13 @property (nonatomic) CGLineJoin lineJoin; 14 15 @end
ArrowLayer.m
#import "ArrowLayer.h" #import <objc/runtime.h> @implementation ArrowLayer @dynamic thickness; @dynamic startRadians; @dynamic lengthRadians; @dynamic headLengthRadians; @dynamic fillColor; @dynamic strokeColor; @dynamic lineWidth; @dynamic lineJoin; + (NSSet *)customPropertyKeys { static NSMutableSet *set; static dispatch_once_t once; dispatch_once(&once, ^{ unsigned int count; objc_property_t *properties = class_copyPropertyList(self, &count); set = [[NSMutableSet alloc] initWithCapacity:count]; for (int i = 0; i < count; ++i) { [set addObject:@(property_getName(properties[i]))]; } free(properties); }); return set; } + (BOOL)needsDisplayForKey:(NSString *)key { return [[self customPropertyKeys] containsObject:key] || [super needsDisplayForKey:key]; } - (id)initWithLayer:(id)layer { if (self = [super initWithLayer:layer]) { for (NSString *key in [self.class customPropertyKeys]) { [self setValue:[layer valueForKey:key] forKey:key]; } } return self; } - (BOOL)needsDisplayOnBoundsChange { return YES; } - (void)drawInContext:(CGContextRef)gc { [self moveOriginToCenterInContext:gc]; [self addArrowToPathInContext:gc]; [self drawPathOfContext:gc]; } - (void)moveOriginToCenterInContext:(CGContextRef)gc { CGRect bounds = self.bounds; CGContextTranslateCTM(gc, CGRectGetMidX(bounds), CGRectGetMidY(bounds)); } - (void)addArrowToPathInContext:(CGContextRef)gc { CGFloat startRadians; CGFloat headRadians; CGFloat tipRadians; [self getStartRadians:&startRadians headRadians:&headRadians tipRadians:&tipRadians]; CGFloat thickness = self.thickness; CGFloat outerRadius = self.bounds.size.width / 2; CGFloat tipRadius = outerRadius - thickness / 2; CGFloat innerRadius = outerRadius - thickness; BOOL outerArcIsClockwise = tipRadians > startRadians; CGContextMoveToPoint(gc, tipRadius * cosf(tipRadians), tipRadius * sinf(tipRadians)); CGContextAddArc(gc, 0, 0, outerRadius, headRadians, startRadians, outerArcIsClockwise); CGContextAddArc(gc, 0, 0, innerRadius, startRadians, headRadians, !outerArcIsClockwise); CGContextClosePath(gc); } - (void)getStartRadians:(CGFloat *)startRadiansOut headRadians:(CGFloat *)headRadiansOut tipRadians:(CGFloat *)tipRadiansOut { *startRadiansOut = self.startRadians; CGFloat lengthRadians = self.lengthRadians; CGFloat headLengthRadians = [self clippedHeadLengthRadians]; // Compute headRadians carefully so it is exactly equal to startRadians if the head length was clipped. *headRadiansOut = *startRadiansOut + (lengthRadians - headLengthRadians); *tipRadiansOut = *startRadiansOut + lengthRadians; } - (CGFloat)clippedHeadLengthRadians { CGFloat lengthRadians = self.lengthRadians; CGFloat headLengthRadians = copysignf(self.headLengthRadians, lengthRadians); if (fabsf(headLengthRadians) > fabsf(lengthRadians)) { headLengthRadians = lengthRadians; } return headLengthRadians; } - (void)drawPathOfContext:(CGContextRef)gc { CGPathDrawingMode mode = 0; [self setFillPropertiesOfContext:gc andUpdateMode:&mode]; [self setStrokePropertiesOfContext:gc andUpdateMode:&mode]; CGContextDrawPath(gc, mode); } - (void)setFillPropertiesOfContext:(CGContextRef)gc andUpdateMode:(CGPathDrawingMode *)modeInOut { UIColor *fillColor = self.fillColor; if (fillColor) { *modeInOut |= kCGPathFill; CGContextSetFillColorWithColor(gc, fillColor.CGColor); } } - (void)setStrokePropertiesOfContext:(CGContextRef)gc andUpdateMode:(CGPathDrawingMode *)modeInOut { UIColor *strokeColor = self.strokeColor; CGFloat lineWidth = self.lineWidth; if (strokeColor && lineWidth > 0) { *modeInOut |= kCGPathStroke; CGContextSetStrokeColorWithColor(gc, strokeColor.CGColor); CGContextSetLineWidth(gc, lineWidth); CGContextSetLineJoin(gc, self.lineJoin); } } @end
See http://stackoverflow.com/a/13578767/77567 for an explanation of this code.
ArrowLayer : A coustom layer animation
标签:
原文地址:http://www.cnblogs.com/ioriwellings/p/4289629.html