码迷,mamicode.com
首页 > 其他好文 > 详细

ArrowLayer : A coustom layer animation

时间:2015-02-13 09:15:56      阅读:124      评论:0      收藏:0      [点我收藏+]

标签:

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!