Skip to content
Closed
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
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

*.xcuserstate
*.xcbkptlist
*.xcscheme

Demo/JPSThumbnailAnnotation.xcodeproj/xcuserdata/
Demo/JPSThumbnailAnnotation.xcworkspace/contents.xcworkspacedata
Demo/Podfile.lock

Demo/Pods/
2 changes: 1 addition & 1 deletion Demo/JPSThumbnailAnnotation-Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.yourcompany.${PRODUCT_NAME:rfc1034identifier}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
Expand Down
1,264 changes: 924 additions & 340 deletions Demo/JPSThumbnailAnnotation.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions Demo/Podfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Uncomment this line to define a global platform for your project
platform :ios, '8.0'

target 'JPSThumbnailAnnotation' do
# Uncomment this line if you're using Swift or would like to use dynamic frameworks
# use_frameworks!

# Pods for JPSThumbnailAnnotation
pod 'JPSThumbnailAnnotation', :path => '../'

end
21 changes: 20 additions & 1 deletion Demo/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,28 @@ - (NSArray *)annotations {
ottawa.coordinate = CLLocationCoordinate2DMake(45.43f, -75.70f);
ottawa.disclosureBlock = ^{ NSLog(@"selected Ottawa"); };

// Sagrada Familia
JPSThumbnail *barcelona = [[JPSThumbnail alloc] init];
barcelona.imageURL = @"https://www.shbarcelona.es/blog/es/wp-content/uploads/2015/10/gaudi-en-barcelona-3-768x741.jpg";
barcelona.title = @"Sagrada Familia";
barcelona.subtitle = @"Barcelona";
barcelona.coordinate = CLLocationCoordinate2DMake(41.4036f, 2.1744f);
barcelona.disclosureBlock = ^{ NSLog(@"selected Barcelona"); };

//Switzerland mountains
JPSThumbnail *switzerland = [[JPSThumbnail alloc] init];
switzerland.imageURL = @"https://pbs.twimg.com/media/CkXS4erWEAA5J3b.jpg";
switzerland.contentMode = UIViewContentModeScaleAspectFit; // By default Aspect fill
switzerland.title = @"Switzerland";
switzerland.subtitle = @"Mountains";
switzerland.coordinate = CLLocationCoordinate2DMake(47.3769f, 8.5417f);
switzerland.disclosureBlock = ^{ NSLog(@"selected Barcelona"); };

return @[[JPSThumbnailAnnotation annotationWithThumbnail:empire],
[JPSThumbnailAnnotation annotationWithThumbnail:apple],
[JPSThumbnailAnnotation annotationWithThumbnail:ottawa]];
[JPSThumbnailAnnotation annotationWithThumbnail:ottawa],
[JPSThumbnailAnnotation annotationWithThumbnail:barcelona],
[JPSThumbnailAnnotation annotationWithThumbnail:switzerland]];
}

#pragma mark - MKMapViewDelegate
Expand Down
4 changes: 3 additions & 1 deletion JPSThumbnailAnnotation.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'JPSThumbnailAnnotation'
s.version = '1.0.0'
s.version = '1.1.0'
s.platform = :ios
s.license = 'MIT'
s.summary = 'A simple mapkit annotation for displaying images and details.'
Expand All @@ -10,7 +10,9 @@ Pod::Spec.new do |s|

s.description = 'JPSThumbnailAnnotation is a simple mapkit annotation view for displaying images with clean design and animations.'

s.ios.deployment_target = '8.0'
s.source_files = 'JPSThumbnailAnnotation/*.{h,m}'
s.frameworks = 'QuartzCore', 'MapKit', 'CoreLocation'
s.dependency 'SDWebImage'
s.requires_arc = true
end
10 changes: 6 additions & 4 deletions JPSThumbnailAnnotation/JPSThumbnail.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ typedef void (^ActionBlock)();

@interface JPSThumbnail : NSObject

@property (nonatomic, strong) UIImage *image;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) NSString *imageURL;
@property (nonatomic) UIViewContentMode contentMode;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *subtitle;
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) ActionBlock disclosureBlock;
@property (nonatomic, copy) ActionBlock disclosureBlock;

@end
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,12 @@

@implementation JPSThumbnail

- (instancetype)init{
self = [super init];
if(self){
self.contentMode = UIViewContentModeScaleAspectFill;
}
return self;
}

@end
100 changes: 63 additions & 37 deletions JPSThumbnailAnnotation/JPSThumbnailAnnotationView.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//

@import QuartzCore;
#import <SDWebImage/UIImageView+WebCache.h>
#import "JPSThumbnailAnnotationView.h"
#import "JPSThumbnail.h"

Expand All @@ -22,6 +23,7 @@ @interface JPSThumbnailAnnotationView ()

@property (nonatomic, readwrite) CLLocationCoordinate2D coordinate;
@property (nonatomic, strong) UIImageView *imageView;
@property (nonatomic, strong) UIImageView *disclosureImageView;
@property (nonatomic, strong) UILabel *titleLabel;
@property (nonatomic, strong) UILabel *subtitleLabel;
@property (nonatomic, strong) ActionBlock disclosureBlock;
Expand Down Expand Up @@ -57,6 +59,7 @@ - (void)setupView {
[self setupImageView];
[self setupTitleLabel];
[self setupSubtitleLabel];
[self setUpDisclosureImage];
[self setupDisclosureButton];
[self setLayerProperties];
[self setDetailGroupAlpha:0.0f];
Expand Down Expand Up @@ -92,17 +95,27 @@ - (void)setupDisclosureButton {
UIButtonType buttonType = iOS7 ? UIButtonTypeSystem : UIButtonTypeCustom;
_disclosureButton = [UIButton buttonWithType:buttonType];
_disclosureButton.tintColor = [UIColor grayColor];
UIImage *disclosureIndicatorImage = [JPSThumbnailAnnotationView disclosureButtonImage];
[_disclosureButton setImage:disclosureIndicatorImage forState:UIControlStateNormal];
_disclosureButton.frame = CGRectMake(kJPSThumbnailAnnotationViewExpandOffset/2.0f + self.frame.size.width/2.0f + 8.0f,
26.5f,
disclosureIndicatorImage.size.width,
disclosureIndicatorImage.size.height);
_disclosureButton.frame = CGRectMake(self.frame.origin.x - kJPSThumbnailAnnotationViewExpandOffset/2+10,
self.frame.origin.y+9,
self.frame.size.width + kJPSThumbnailAnnotationViewExpandOffset-20,
self.frame.size.height-33);

[_disclosureButton addTarget:self action:@selector(didTapDisclosureButton) forControlEvents:UIControlEventTouchDown];
[self addSubview:_disclosureButton];
}

- (void) setUpDisclosureImage{
_disclosureImageView.tintColor = [UIColor grayColor];
UIImage *disclosureIndicatorImage = [JPSThumbnailAnnotationView disclosureButtonImage];
_disclosureImageView = [[ UIImageView alloc ] initWithImage:disclosureIndicatorImage];
_disclosureImageView.frame = CGRectMake(kJPSThumbnailAnnotationViewExpandOffset/2.0f + self.frame.size.width/2.0f + 8.0f,
26.5f,
disclosureIndicatorImage.size.width,
disclosureIndicatorImage.size.height);

[self addSubview:_disclosureImageView];
}

- (void)setLayerProperties {
_bgLayer = [CAShapeLayer layer];
CGPathRef path = [self newBubbleWithRect:self.bounds];
Expand All @@ -126,7 +139,20 @@ - (void)updateWithThumbnail:(JPSThumbnail *)thumbnail {
self.coordinate = thumbnail.coordinate;
self.titleLabel.text = thumbnail.title;
self.subtitleLabel.text = thumbnail.subtitle;
self.imageView.image = thumbnail.image;
self.imageView.contentMode = thumbnail.contentMode;
if(thumbnail.imageURL){
[self.imageView setIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.imageView setShowActivityIndicatorView:YES];
[self.imageView sd_setImageWithURL:[NSURL URLWithString:thumbnail.imageURL]
placeholderImage:thumbnail.image
options:SDWebImageAllowInvalidSSLCertificates
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
[self.imageView setShowActivityIndicatorView:NO];
}];
}
else{
self.imageView.image = thumbnail.image;
}
self.disclosureBlock = thumbnail.disclosureBlock;
}

Expand All @@ -146,30 +172,30 @@ - (void)didDeselectAnnotationViewInMap:(MKMapView *)mapView {

- (CGPathRef)newBubbleWithRect:(CGRect)rect {
CGFloat stroke = 1.0f;
CGFloat radius = 7.0f;
CGMutablePathRef path = CGPathCreateMutable();
CGFloat parentX = rect.origin.x + rect.size.width/2.0f;
// Determine Size
rect.size.width -= stroke + 14.0f;
rect.size.height -= stroke + 29.0f;
rect.origin.x += stroke / 2.0f + 7.0f;
rect.origin.y += stroke / 2.0f + 7.0f;
CGFloat radius = 7.0f;
CGMutablePathRef path = CGPathCreateMutable();
CGFloat parentX = rect.origin.x + rect.size.width/2.0f;
// Determine Size
rect.size.width -= stroke + 14.0f;
rect.size.height -= stroke + 29.0f;
rect.origin.x += stroke / 2.0f + 7.0f;
rect.origin.y += stroke / 2.0f + 7.0f;

// Create Callout Bubble Path
CGPathMoveToPoint(path, NULL, rect.origin.x, rect.origin.y + radius);
CGPathAddLineToPoint(path, NULL, rect.origin.x, rect.origin.y + rect.size.height - radius);
CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI, M_PI_2, 1);
CGPathAddLineToPoint(path, NULL, parentX - 14.0f, rect.origin.y + rect.size.height);
CGPathAddLineToPoint(path, NULL, parentX, rect.origin.y + rect.size.height + 14.0f);
CGPathAddLineToPoint(path, NULL, parentX + 14.0f, rect.origin.y + rect.size.height);
CGPathAddLineToPoint(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height);
CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI_2, 0.0f, 1.0f);
CGPathAddLineToPoint(path, NULL, rect.origin.x + rect.size.width, rect.origin.y + radius);
CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, radius, 0.0f, -M_PI_2, 1.0f);
CGPathAddLineToPoint(path, NULL, rect.origin.x + radius, rect.origin.y);
CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + radius, radius, -M_PI_2, M_PI, 1.0f);
CGPathCloseSubpath(path);
// Create Callout Bubble Path
CGPathMoveToPoint(path, NULL, rect.origin.x, rect.origin.y + radius);
CGPathAddLineToPoint(path, NULL, rect.origin.x, rect.origin.y + rect.size.height - radius);
CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + rect.size.height - radius, radius, M_PI, M_PI_2, 1);
CGPathAddLineToPoint(path, NULL, parentX - 14.0f, rect.origin.y + rect.size.height);
CGPathAddLineToPoint(path, NULL, parentX, rect.origin.y + rect.size.height + 14.0f);
CGPathAddLineToPoint(path, NULL, parentX + 14.0f, rect.origin.y + rect.size.height);
CGPathAddLineToPoint(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height);
CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + rect.size.height - radius, radius, M_PI_2, 0.0f, 1.0f);
CGPathAddLineToPoint(path, NULL, rect.origin.x + rect.size.width, rect.origin.y + radius);
CGPathAddArc(path, NULL, rect.origin.x + rect.size.width - radius, rect.origin.y + radius, radius, 0.0f, -M_PI_2, 1.0f);
CGPathAddLineToPoint(path, NULL, rect.origin.x + radius, rect.origin.y);
CGPathAddArc(path, NULL, rect.origin.x + radius, rect.origin.y + radius, radius, -M_PI_2, M_PI, 1.0f);
CGPathCloseSubpath(path);
return path;
}

Expand All @@ -179,6 +205,7 @@ - (void)setDetailGroupAlpha:(CGFloat)alpha {
self.disclosureButton.alpha = alpha;
self.titleLabel.alpha = alpha;
self.subtitleLabel.alpha = alpha;
self.disclosureImageView.alpha = alpha;
}

- (void)expand {
Expand All @@ -187,8 +214,7 @@ - (void)expand {
self.state = JPSThumbnailAnnotationViewStateAnimating;

[self animateBubbleWithDirection:JPSThumbnailAnnotationViewAnimationDirectionGrow];
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width+kJPSThumbnailAnnotationViewExpandOffset, self.frame.size.height);
self.centerOffset = CGPointMake(kJPSThumbnailAnnotationViewExpandOffset/2.0f, -kJPSThumbnailAnnotationViewVerticalOffset);
self.bounds = CGRectMake(self.bounds.origin.x-kJPSThumbnailAnnotationViewExpandOffset/2, self.bounds.origin.y, self.bounds.size.width+kJPSThumbnailAnnotationViewExpandOffset, self.bounds.size.height);
[UIView animateWithDuration:kJPSThumbnailAnnotationViewAnimationDuration/2.0f delay:kJPSThumbnailAnnotationViewAnimationDuration options:UIViewAnimationOptionCurveEaseInOut animations:^{
[self setDetailGroupAlpha:1.0f];
} completion:^(BOOL finished) {
Expand All @@ -200,11 +226,11 @@ - (void)shrink {
if (self.state != JPSThumbnailAnnotationViewStateExpanded) return;

self.state = JPSThumbnailAnnotationViewStateAnimating;

self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
self.frame.size.width - kJPSThumbnailAnnotationViewExpandOffset,
self.frame.size.height);
self.bounds = CGRectMake(self.bounds.origin.x + kJPSThumbnailAnnotationViewExpandOffset/2,
self.bounds.origin.y,
self.bounds.size.width - kJPSThumbnailAnnotationViewExpandOffset,
self.bounds.size.height);

[UIView animateWithDuration:kJPSThumbnailAnnotationViewAnimationDuration/2.0f
delay:0.0f
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# JPSThumbnailAnnotation

JPSThumbnailAnnotation is a simple mapkit annotation view for displaying images with clean design and animations. It is 100% programmatically drawn and styled for iOS 7.
JPSThumbnailAnnotation is a simple mapkit annotation view for displaying images with clean design and animations. It is 100% programmatically drawn and styled for iOS 8, now including loading image from urls asyncronously.

![JPSThumbnailAnnotation in action](screenshots2.jpg)

Expand All @@ -10,10 +10,6 @@ JPSThumbnailAnnotation is a simple mapkit annotation view for displaying images

Add `pod 'JPSThumbnailAnnotation'` to your Podfile.

### Manually

Copy the `JPSThumbnailAnnotation` folder to your Xcode project and link the `MapKit`, `QuartzCore` and `CoreLocation` libraries.

## Usage

(see sample Xcode project in `/Demo`)
Expand All @@ -23,6 +19,10 @@ You add an `JPSThumbnailAnnotation` just like any other `MKAnnotation`. The anno
``` objc
JPSThumbnail *thumbnail = [[JPSThumbnail alloc] init];
thumbnail.image = [UIImage imageNamed:@"empire.jpg"];

// If imgUrl is defined, the image will be loaded asyncronously from URL
thumbnail.imgUrl = @"https://www.imageUrlExampleDomain.com/exampleImageName.png";

thumbnail.title = @"Empire State Building";
thumbnail.subtitle = @"NYC Landmark";
thumbnail.coordinate = CLLocationCoordinate2DMake(40.75f, -73.99f);
Expand Down