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

[TIMOB-12582] iOS: Adding custom views in the pin #3887

Merged
merged 7 commits into from
Feb 25, 2013
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 10 additions & 1 deletion apidoc/Titanium/Map/Annotation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ properties:
Must be set before the annotation is added to the map view.
type: Boolean

- name: customView
summary: Defines a custom view to be used by the annotation.
description: |
A custom View to display for the annotation. **User interaction is disabled on the view.**
No view interaction events (click, touchstart etc) will be fired.
type: Titanium.UI.View
platforms: [iphone, ipad]
since: "3.1.0"

- name: draggable
summary: Determines whether the pin can be dragged by the user.
description: |
Expand All @@ -66,7 +75,7 @@ properties:
- name: image
summary: Image to use for the the pin.
description: |
The image can be specified using a local URL or an image `Blob`.
The image can be specified using a local URL or an image `Blob`. This is ignored if the customeView property is set.
type: [String, Titanium.Blob]
default: If not specified, a standard map pin image is used.

Expand Down
2 changes: 1 addition & 1 deletion iphone/Classes/TiMapAnnotationProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

@class TiMapViewProxy;

@interface TiMapAnnotationProxy : TiViewProxy<MKAnnotation> {
@interface TiMapAnnotationProxy : TiViewProxy<MKAnnotation, TiProxyObserver> {
@private
int tag;
TiMapViewProxy *delegate;
Expand Down
22 changes: 22 additions & 0 deletions iphone/Classes/TiMapAnnotationProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,28 @@ -(void)setImage:(id)image
}
}

-(void)setCustomView:(id)customView
{
id current = [self valueForUndefinedKey:@"customView"];
[self replaceValue:customView forKey:@"customView" notification:NO];
if ([current isEqual: customView] == NO)
{
[current setProxyObserver:nil];
[self forgetProxy:current];
[self rememberProxy:customView];
[customView setProxyObserver:self];
[self setNeedsRefreshingWithSelection:YES];
}
}

-(void)proxyDidRelayout:(id)sender
{
id current = [self valueForUndefinedKey:@"customView"];
if ( ([current isEqual:sender] == YES) && (self.placed) ) {
[self setNeedsRefreshingWithSelection:YES];
}
}


-(int)tag
{
Expand Down
27 changes: 27 additions & 0 deletions iphone/Classes/TiMapCustomAnnotationView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2013 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
#import "TiBase.h"

#ifdef USE_TI_MAP

#import <MapKit/MapKit.h>
#import "TiMapView.h"
#import "TiViewProxy.h"

@interface TiMapCustomAnnotationView : MKAnnotationView<TiMapAnnotation> {
@private
NSString * lastHitName;
TiViewProxy* theProxy;
UIView* wrapperView;
}

- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier map:(TiMapView*)map;
- (NSString *)lastHitName;
- (void)setProxy:(TiViewProxy*)customView;

@end
#endif
97 changes: 97 additions & 0 deletions iphone/Classes/TiMapCustomAnnotationView.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2013 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
#import "TiBase.h"

#ifdef USE_TI_MAP

#import "TiMapCustomAnnotationView.h"

@implementation TiMapCustomAnnotationView

- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier map:(TiMapView*)map
{
if (self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier]) {
self.backgroundColor = [UIColor clearColor];
wrapperView = [[UIView alloc] initWithFrame:CGRectZero];
wrapperView.userInteractionEnabled = false;
[self addSubview:wrapperView];
}
return self;
}

- (void)setProxy:(TiViewProxy*)customView;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

; at the end

{
if (theProxy != customView) {
[[theProxy view] removeFromSuperview];
RELEASE_TO_NIL(theProxy);
[self initWithProxy:customView];
}
else {
TiUIView* theView = [theProxy barButtonViewForSize:CGSizeZero];
self.frame = wrapperView.frame = [theView bounds];
}
}

- (void)initWithProxy:(TiViewProxy*)customView
{
theProxy = [customView retain];
TiUIView* theView = [theProxy barButtonViewForSize:CGSizeZero];
self.frame = wrapperView.frame = [theView bounds];
[wrapperView addSubview:theView];
}

-(void)dealloc
{
RELEASE_TO_NIL(wrapperView);
RELEASE_TO_NIL(lastHitName);
RELEASE_TO_NIL(theProxy);
[super dealloc];
}

-(NSString *)lastHitName
{
NSString * result = lastHitName;
[lastHitName autorelease];
lastHitName = nil;
return result;
}

- (UIView *)hitTest:(CGPoint) point withEvent:(UIEvent *)event
{
UIView * result = [super hitTest:point withEvent:event];

if (result==nil) {
for (UIView * ourSubView in [self subviews]) {
CGPoint subPoint = [self convertPoint:point toView:ourSubView];
for (UIView * ourSubSubView in [ourSubView subviews]) {
if (CGRectContainsPoint([ourSubSubView frame], subPoint) && [ourSubSubView isKindOfClass:[UILabel class]]) {
NSString * labelText = [(UILabel *)ourSubSubView text];
TiMapAnnotationProxy * ourProxy = (TiMapAnnotationProxy *)[self annotation];
RELEASE_TO_NIL(lastHitName);
if ([labelText isEqualToString:[ourProxy title]]) {
lastHitName = [@"title" retain];
}
else if ([labelText isEqualToString:[ourProxy subtitle]]) {
lastHitName = [@"subtitle" retain];
}
return nil;
}
}
if (CGRectContainsPoint([ourSubView bounds], subPoint)) {
RELEASE_TO_NIL(lastHitName);
lastHitName = [@"annotation" retain];
return nil;
}
}
}
RELEASE_TO_NIL(lastHitName);
return result;
}

@end

#endif
100 changes: 56 additions & 44 deletions iphone/Classes/TiMapView.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#import "TiMapAnnotationProxy.h"
#import "TiMapPinAnnotationView.h"
#import "TiMapImageAnnotationView.h"
#import "TiMapCustomAnnotationView.h"

@implementation TiMapView

Expand Down Expand Up @@ -128,6 +129,7 @@ -(void)refreshAnnotation:(TiMapAnnotationProxy*)proxy readd:(BOOL)yn
{
NSArray *selected = map.selectedAnnotations;
BOOL wasSelected = [selected containsObject:proxy]; //If selected == nil, this still returns FALSE.
ignoreClicks = YES;
if (yn==NO)
{
[map deselectAnnotation:proxy animated:NO];
Expand All @@ -142,6 +144,7 @@ -(void)refreshAnnotation:(TiMapAnnotationProxy*)proxy readd:(BOOL)yn
{
[map selectAnnotation:proxy animated:NO];
}
ignoreClicks = NO;
}

#pragma mark Public APIs
Expand Down Expand Up @@ -678,60 +681,69 @@ - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)aview ca
// For MapKit provided annotations (eg. MKUserLocation) return nil to use the MapKit provided annotation view.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[TiMapAnnotationProxy class]])
{
TiMapAnnotationProxy *ann = (TiMapAnnotationProxy*)annotation;
id imagePath = [ann valueForUndefinedKey:@"image"];
UIImage *image = [TiUtils image:imagePath proxy:ann];
NSString *identifier = (image!=nil) ? @"timap-image":@"timap-pin";
MKAnnotationView *annView = nil;
if ([annotation isKindOfClass:[TiMapAnnotationProxy class]]) {
TiMapAnnotationProxy *ann = (TiMapAnnotationProxy*)annotation;
id customView = [ann valueForUndefinedKey:@"customView"];
if ( (customView == nil) || (customView == [NSNull null]) || (![customView isKindOfClass:[TiViewProxy class]]) ){
customView = nil;
}
NSString *identifier = nil;
UIImage* image = nil;
if (customView == nil) {
id imagePath = [ann valueForUndefinedKey:@"image"];
image = [TiUtils image:imagePath proxy:ann];
identifier = (image!=nil) ? @"timap-image":@"timap-pin";
}
else {
identifier = @"timap-customView";
}
MKAnnotationView *annView = nil;

annView = (MKAnnotationView*) [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
annView = (MKAnnotationView*) [mapView dequeueReusableAnnotationViewWithIdentifier:identifier];

if (annView==nil)
{
if ([identifier isEqualToString:@"timap-image"])
{
if (annView==nil) {
if ([identifier isEqualToString:@"timap-customView"]) {
annView = [[[TiMapCustomAnnotationView alloc] initWithAnnotation:ann reuseIdentifier:identifier map:self] autorelease];
}
else if ([identifier isEqualToString:@"timap-image"]) {
annView=[[[TiMapImageAnnotationView alloc] initWithAnnotation:ann reuseIdentifier:identifier map:self image:image] autorelease];
}
else
{
else {
annView=[[[TiMapPinAnnotationView alloc] initWithAnnotation:ann reuseIdentifier:identifier map:self] autorelease];
}
}
if ([identifier isEqualToString:@"timap-image"])
{
if ([identifier isEqualToString:@"timap-customView"]) {
[((TiMapCustomAnnotationView*)annView) setProxy:customView];
}
else if ([identifier isEqualToString:@"timap-image"]) {
annView.image = image;
}
else
{
MKPinAnnotationView *pinview = (MKPinAnnotationView*)annView;
pinview.pinColor = [ann pinColor];
pinview.animatesDrop = [ann animatesDrop] && ![(TiMapAnnotationProxy *)annotation placed];
annView.calloutOffset = CGPointMake(-8, 0);
}
annView.canShowCallout = YES;
annView.enabled = YES;
UIView *left = [ann leftViewAccessory];
UIView *right = [ann rightViewAccessory];
if (left!=nil)
{
annView.leftCalloutAccessoryView = left;
}
if (right!=nil)
{
annView.rightCalloutAccessoryView = right;
}
else {
MKPinAnnotationView *pinview = (MKPinAnnotationView*)annView;
pinview.pinColor = [ann pinColor];
pinview.animatesDrop = [ann animatesDrop] && ![(TiMapAnnotationProxy *)annotation placed];
annView.calloutOffset = CGPointMake(-8, 0);
}
annView.canShowCallout = YES;
annView.enabled = YES;
UIView *left = [ann leftViewAccessory];
UIView *right = [ann rightViewAccessory];
if (left!=nil) {
annView.leftCalloutAccessoryView = left;
}
if (right!=nil) {
annView.rightCalloutAccessoryView = right;
}

BOOL draggable = [TiUtils boolValue: [ann valueForUndefinedKey:@"draggable"]];
if (draggable && [[MKAnnotationView class] instancesRespondToSelector:NSSelectorFromString(@"isDraggable")])
[annView performSelector:NSSelectorFromString(@"setDraggable:") withObject:[NSNumber numberWithBool:YES]];
BOOL draggable = [TiUtils boolValue: [ann valueForUndefinedKey:@"draggable"]];
if (draggable && [[MKAnnotationView class] instancesRespondToSelector:NSSelectorFromString(@"isDraggable")])
[annView performSelector:NSSelectorFromString(@"setDraggable:") withObject:[NSNumber numberWithBool:YES]];

annView.userInteractionEnabled = YES;
annView.tag = [ann tag];
return annView;
}
return nil;
annView.userInteractionEnabled = YES;
annView.tag = [ann tag];
return annView;
}
return nil;
}


Expand All @@ -749,7 +761,7 @@ - (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views
/*Image Annotation don't have any animation of its own.
*So in this case we do a custom animation, to place the
*image annotation on top of the mapview.*/
if([thisView isKindOfClass:[TiMapImageAnnotationView class]])
if([thisView isKindOfClass:[TiMapImageAnnotationView class]] || [thisView isKindOfClass:[TiMapCustomAnnotationView class]])
{
TiMapAnnotationProxy *anntProxy = [self proxyForAnnotation:thisView];
if([anntProxy animatesDrop] && ![anntProxy placed])
Expand Down
3 changes: 2 additions & 1 deletion iphone/Classes/TiViewProxy.m
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,8 @@ - (TiUIView *)barButtonViewForSize:(CGSize)bounds
[self windowWillOpen];
[self setParentVisible:YES];
[self layoutChildren:NO];

[self refreshSize];
[self refreshPosition];
return barButtonView;
}

Expand Down