Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OSX support #8

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions SVPulsingAnnotationView/SVPulsingAnnotationView.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@

#import <MapKit/MapKit.h>

#if TARGET_OS_IPHONE
#define SVColor UIColor
#define SVImage UIImage
#else
#define SVColor NSColor
#define SVImage NSImage
#endif

@interface SVPulsingAnnotationView : MKAnnotationView

@property (nonatomic, strong) UIColor *annotationColor; // default is same as MKUserLocationView
@property (nonatomic, strong) UIColor *pulseColor; // default is same as annotationColor
@property (nonatomic, strong) UIImage *image; // default is nil
@property (nonatomic, strong) SVColor *annotationColor; // default is same as MKUserLocationView
@property (nonatomic, strong) SVColor *pulseColor; // default is same as annotationColor
@property (nonatomic, strong) SVImage *image; // default is nil

@property (nonatomic, readwrite) float pulseScaleFactor; // default is 5.3
@property (nonatomic, readwrite) NSTimeInterval pulseAnimationDuration; // default is 1s
Expand Down
86 changes: 66 additions & 20 deletions SVPulsingAnnotationView/SVPulsingAnnotationView.m
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,19 @@
#import "SVPulsingAnnotationView.h"
#import <QuartzCore/QuartzCore.h>

#if TARGET_OS_IPHONE
#define SVImageView UIImageView
#define SVView UIView
#else
#define SVImageView NSImageView
#define SVView NSView
#endif

@interface SVPulsingAnnotationView ()

@property (nonatomic, strong) CALayer *shinyDotLayer;
@property (nonatomic, strong) CALayer *glowingHaloLayer;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) SVImageView *imageView;

@property (nonatomic, strong) CALayer *whiteDotLayer;
@property (nonatomic, strong) CALayer *colorDotLayer;
Expand All @@ -38,12 +46,16 @@ - (id)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString
if(self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) {
self.layer.anchorPoint = CGPointMake(0.5, 0.5);
self.calloutOffset = CGPointMake(0, 4);
#if TARGET_OS_IPHONE
self.bounds = CGRectMake(0, 0, 22, 22);
#else
self.frame = NSMakeRect(0, 0, 22, 22);
#endif
self.pulseScaleFactor = 5.3;
self.pulseAnimationDuration = 1.5;
self.outerPulseAnimationDuration = 3;
self.delayBetweenPulseCycles = 0;
self.annotationColor = [UIColor colorWithRed:0.000 green:0.478 blue:1.000 alpha:1];
self.annotationColor = [SVColor colorWithRed:0.000 green:0.478 blue:1.000 alpha:1];
}
return self;
}
Expand Down Expand Up @@ -74,7 +86,11 @@ - (void)rebuildLayers {
[self.layer addSublayer:self.colorDotLayer];
}

- (void)willMoveToSuperview:(UIView *)newSuperview {
#if TARGET_OS_IPHONE
- (void)willMoveToSuperview:(SVView *)newSuperview {
#else
-(void)viewWillMoveToSuperview:(SVView *)newSuperview {
#endif
if(newSuperview) {
[self rebuildLayers];
[self popIn];
Expand All @@ -93,16 +109,17 @@ - (void)popIn {

#pragma mark - Setters

- (void)setAnnotationColor:(UIColor *)annotationColor {
- (void)setAnnotationColor:(SVColor *)annotationColor {
if(CGColorGetNumberOfComponents(annotationColor.CGColor) == 2) {
float white = CGColorGetComponents(annotationColor.CGColor)[0];
float alpha = CGColorGetComponents(annotationColor.CGColor)[1];
annotationColor = [UIColor colorWithRed:white green:white blue:white alpha:alpha];
annotationColor = [SVColor colorWithRed:white green:white blue:white alpha:alpha];
}

_annotationColor = annotationColor;
#if TARGET_OS_IPHONE
_imageView.tintColor = annotationColor;
#endif
if(self.superview)
[self rebuildLayers];
}
Expand All @@ -121,21 +138,26 @@ - (void)setPulseAnimationDuration:(NSTimeInterval)pulseAnimationDuration {
[self rebuildLayers];
}

- (void)setImage:(UIImage *)image {
- (void)setImage:(SVImage *)image {
_image = image;

if(self.superview)
[self rebuildLayers];

#if TARGET_OS_IPHONE
self.imageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
self.imageView.bounds = CGRectMake(0, 0, ceil(image.size.width), ceil(image.size.height));

self.imageView.center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
self.imageView.tintColor = self.annotationColor;
#else
self.imageView.image = _image;
#endif
}

#pragma mark - Getters

- (UIColor *)pulseColor {
- (SVColor *)pulseColor {
if(!_pulseColor)
return self.annotationColor;
return _pulseColor;
Expand Down Expand Up @@ -173,10 +195,12 @@ - (CAAnimationGroup*)pulseAnimationGroup {

#pragma mark - Graphics

- (UIImageView *)imageView {
- (SVImageView *)imageView {
if(!_imageView) {
_imageView = [[UIImageView alloc] initWithFrame:self.bounds];
_imageView = [[SVImageView alloc] initWithFrame:self.bounds];
#if TARGET_OS_IPHONE
_imageView.contentMode = UIViewContentModeTopLeft;
#endif
}
return _imageView;
}
Expand All @@ -185,16 +209,21 @@ - (CALayer*)whiteDotLayer {
if(!_whiteDotLayer) {
_whiteDotLayer = [CALayer layer];
_whiteDotLayer.bounds = self.bounds;
_whiteDotLayer.contents = (id)[self circleImageWithColor:[UIColor whiteColor] height:self.bounds.size.height].CGImage;
#if TARGET_OS_IPHONE
_whiteDotLayer.contents = (id)[self circleImageWithColor:[SVColor whiteColor] height:self.bounds.size.height].CGImage;
_whiteDotLayer.contentsScale = [UIScreen mainScreen].scale;
_whiteDotLayer.rasterizationScale = [UIScreen mainScreen].scale;
#else
_whiteDotLayer.contents = [self circleImageWithColor:[SVColor whiteColor] height:self.bounds.size.height];
#endif
_whiteDotLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
_whiteDotLayer.contentsGravity = kCAGravityCenter;
_whiteDotLayer.contentsScale = [UIScreen mainScreen].scale;
_whiteDotLayer.shadowColor = [UIColor blackColor].CGColor;

_whiteDotLayer.shadowColor = [SVColor blackColor].CGColor;
_whiteDotLayer.shadowOffset = CGSizeMake(0, 2);
_whiteDotLayer.shadowRadius = 3;
_whiteDotLayer.shadowOpacity = 0.3;
_whiteDotLayer.shouldRasterize = YES;
_whiteDotLayer.rasterizationScale = [UIScreen mainScreen].scale;
}
return _whiteDotLayer;
}
Expand All @@ -204,7 +233,11 @@ - (CALayer*)colorDotLayer {
_colorDotLayer = [CALayer layer];
CGFloat width = self.bounds.size.width-6;
_colorDotLayer.bounds = CGRectMake(0, 0, width, width);

#if TARGET_OS_IPHONE
_colorDotLayer.allowsGroupOpacity = YES;
#endif

_colorDotLayer.backgroundColor = self.annotationColor.CGColor;
_colorDotLayer.cornerRadius = width/2;
_colorDotLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
Expand All @@ -213,7 +246,7 @@ - (CALayer*)colorDotLayer {

if(self.delayBetweenPulseCycles != INFINITY) {
CAMediaTimingFunction *defaultCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];

CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.duration = self.pulseAnimationDuration;
animationGroup.repeatCount = INFINITY;
Expand All @@ -222,7 +255,7 @@ - (CALayer*)colorDotLayer {
animationGroup.timingFunction = defaultCurve;
animationGroup.speed = 1;
animationGroup.fillMode = kCAFillModeBoth;

CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale.xy"];
pulseAnimation.fromValue = @0.8;
pulseAnimation.toValue = @1;
Expand All @@ -234,13 +267,13 @@ - (CALayer*)colorDotLayer {
opacityAnimation.duration = self.pulseAnimationDuration;

animationGroup.animations = @[pulseAnimation, opacityAnimation];

dispatch_async(dispatch_get_main_queue(), ^(void) {
[_colorDotLayer addAnimation:animationGroup forKey:@"pulse"];
});
}
});

}
return _colorDotLayer;
}
Expand All @@ -251,7 +284,11 @@ - (CALayer *)colorHaloLayer {
CGFloat width = self.bounds.size.width*self.pulseScaleFactor;
_colorHaloLayer.bounds = CGRectMake(0, 0, width, width);
_colorHaloLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);

#if TARGET_OS_IPHONE
_colorHaloLayer.contentsScale = [UIScreen mainScreen].scale;
#endif

_colorHaloLayer.backgroundColor = self.pulseColor.CGColor;
_colorHaloLayer.cornerRadius = width/2;
_colorHaloLayer.opacity = 0;
Expand All @@ -269,20 +306,29 @@ - (CALayer *)colorHaloLayer {
return _colorHaloLayer;
}

- (UIImage*)circleImageWithColor:(UIColor*)color height:(float)height {
- (SVImage*)circleImageWithColor:(SVColor*)color height:(float)height {
#if TARGET_OS_IPHONE
UIGraphicsBeginImageContextWithOptions(CGSizeMake(height, height), NO, 0);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

UIBezierPath* fillPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, height, height)];
[color setFill];
[fillPath fill];

UIImage *dotImage = UIGraphicsGetImageFromCurrentImageContext();
SVImage *dotImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

CGColorSpaceRelease(colorSpace);

return dotImage;
#else
return [NSImage imageWithSize:NSMakeSize(height, height) flipped:NO drawingHandler:^BOOL(NSRect dstRect) {
NSBezierPath *fillPath = [NSBezierPath bezierPathWithOvalInRect:dstRect];
[color setFill];
[fillPath fill];
return YES;
}];
#endif
}

@end