Authored by Justin R. Miller

refs #5: first cut of RMUserTrackingBarButtonItem

//
// RMUserTrackingBarButtonItem.h
// MapView
//
// Created by Justin Miller on 5/10/12.
// Copyright (c) 2012 MapBox / Development Seed. All rights reserved.
//
#import <UIKit/UIKit.h>
@class RMMapView;
@interface RMUserTrackingBarButtonItem : UIBarButtonItem
- (id)initWithMapView:(RMMapView *)mapView;
@property (nonatomic, retain) RMMapView *mapView;
@end
... ...
//
// RMUserTrackingBarButtonItem.m
// MapView
//
// Created by Justin Miller on 5/10/12.
// Copyright (c) 2012 MapBox / Development Seed. All rights reserved.
//
#import "RMUserTrackingBarButtonItem.h"
#import "RMMapView.h"
#import "RMUserLocation.h"
typedef enum {
RMUserTrackingButtonStateActivity = 0,
RMUserTrackingButtonStateLocation = 1,
RMUserTrackingButtonStateHeading = 2
} RMUserTrackingButtonState;
@interface RMUserTrackingBarButtonItem ()
@property (nonatomic, retain) UISegmentedControl *segmentedControl;
@property (nonatomic, retain) UIImageView *buttonImageView;
@property (nonatomic, retain) UIActivityIndicatorView *activityView;
@property (nonatomic) RMUserTrackingButtonState state;
- (void)updateAppearance;
- (void)changeMode:(id)sender;
@end
#pragma mark -
@implementation RMUserTrackingBarButtonItem
@synthesize mapView=_mapView;
@synthesize segmentedControl;
@synthesize buttonImageView;
@synthesize activityView;
@synthesize state;
- (id)initWithMapView:(RMMapView *)mapView
{
if (!(self = [super initWithCustomView:[[UIControl alloc] initWithFrame:CGRectMake(0, 0, 32, 32)]]))
return nil;
segmentedControl = [[[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObject:@""]] retain];
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
[segmentedControl setWidth:32.0 forSegmentAtIndex:0];
segmentedControl.userInteractionEnabled = NO;
segmentedControl.tintColor = self.tintColor;
segmentedControl.center = self.customView.center;
[self.customView addSubview:segmentedControl];
buttonImageView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"TrackingLocation.png"]] retain];
buttonImageView.contentMode = UIViewContentModeCenter;
buttonImageView.frame = CGRectMake(0, 0, 32, 32);
buttonImageView.center = self.customView.center;
buttonImageView.userInteractionEnabled = NO;
[self.customView addSubview:buttonImageView];
activityView = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite] retain];
activityView.hidesWhenStopped = YES;
activityView.center = self.customView.center;
activityView.userInteractionEnabled = NO;
[self.customView addSubview:activityView];
[((UIControl *)self.customView) addTarget:self action:@selector(changeMode:) forControlEvents:UIControlEventTouchUpInside];
_mapView = [mapView retain];
[_mapView addObserver:self forKeyPath:@"userTrackingMode" options:NSKeyValueObservingOptionNew context:nil];
[self updateAppearance];
return self;
}
- (void)dealloc
{
[segmentedControl release]; segmentedControl = nil;
[buttonImageView release]; buttonImageView = nil;
[activityView release]; activityView = nil;
[_mapView removeObserver:self forKeyPath:@"userTrackingMode"];
[_mapView release]; _mapView = nil;
[super dealloc];
}
#pragma mark -
- (void)setMapView:(RMMapView *)newMapView
{
if ( ! [newMapView isEqual:_mapView])
{
[_mapView removeObserver:self forKeyPath:@"userTrackingMode"];
[_mapView release];
_mapView = [newMapView retain];
[_mapView addObserver:self forKeyPath:@"userTrackingMode" options:NSKeyValueObservingOptionNew context:nil];
[self updateAppearance];
}
}
- (void)setTintColor:(UIColor *)newTintColor
{
[super setTintColor:newTintColor];
segmentedControl.tintColor = newTintColor;
}
#pragma mark -
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
[self updateAppearance];
}
#pragma mark -
- (void)updateAppearance
{
segmentedControl.selectedSegmentIndex = (_mapView.userTrackingMode == RMUserTrackingModeNone ? UISegmentedControlNoSegment : 0);
if ( ! _mapView.userLocation || ! _mapView.userLocation.location)
{
if (state != RMUserTrackingButtonStateActivity)
{
[UIView animateWithDuration:0.25
animations:^(void)
{
buttonImageView.transform = CGAffineTransformMakeScale(0.01, 0.01);
activityView.transform = CGAffineTransformMakeScale(0.01, 0.01);
}
completion:^(BOOL finished)
{
buttonImageView.hidden = YES;
[activityView startAnimating];
[UIView animateWithDuration:0.25 animations:^(void)
{
buttonImageView.transform = CGAffineTransformIdentity;
activityView.transform = CGAffineTransformIdentity;
}];
}];
state = RMUserTrackingButtonStateActivity;
}
}
else
{
if ((_mapView.userTrackingMode != RMUserTrackingModeFollowWithHeading && state != RMUserTrackingButtonStateLocation) ||
(_mapView.userTrackingMode == RMUserTrackingModeFollowWithHeading && state != RMUserTrackingButtonStateHeading))
{
[UIView animateWithDuration:0.25
animations:^(void)
{
buttonImageView.transform = CGAffineTransformMakeScale(0.01, 0.01);
activityView.transform = CGAffineTransformMakeScale(0.01, 0.01);
}
completion:^(BOOL finished)
{
buttonImageView.image = [UIImage imageNamed:(_mapView.userTrackingMode == RMUserTrackingModeFollowWithHeading ? @"TrackingHeading.png" : @"TrackingLocation.png")];
buttonImageView.hidden = NO;
[activityView stopAnimating];
[UIView animateWithDuration:0.25 animations:^(void)
{
buttonImageView.transform = CGAffineTransformIdentity;
activityView.transform = CGAffineTransformIdentity;
}];
}];
state = (_mapView.userTrackingMode == RMUserTrackingModeFollowWithHeading ? RMUserTrackingButtonStateHeading : RMUserTrackingButtonStateLocation);
}
}
}
- (void)changeMode:(id)sender
{
if (_mapView)
{
switch (_mapView.userTrackingMode)
{
case RMUserTrackingModeNone:
default:
{
_mapView.userTrackingMode = RMUserTrackingModeFollow;
break;
}
case RMUserTrackingModeFollow:
{
if ([CLLocationManager headingAvailable])
_mapView.userTrackingMode = RMUserTrackingModeFollowWithHeading;
else
_mapView.userTrackingMode = RMUserTrackingModeNone;
break;
}
case RMUserTrackingModeFollowWithHeading:
{
_mapView.userTrackingMode = RMUserTrackingModeNone;
break;
}
}
}
[self updateAppearance];
}
@end
... ...
... ... @@ -158,6 +158,8 @@
DD8FD7541559E4A40044D96F /* RMUserLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = DD8FD7521559E4A40044D96F /* RMUserLocation.h */; };
DD8FD7551559E4A40044D96F /* RMUserLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = DD8FD7531559E4A40044D96F /* RMUserLocation.m */; };
DD96559215264C810008517A /* RMMapBoxSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DD96559015264C810008517A /* RMMapBoxSource.h */; };
DDA6B8BD155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.h in Headers */ = {isa = PBXBuildFile; fileRef = DDA6B8BB155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.h */; };
DDA6B8BE155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.m in Sources */ = {isa = PBXBuildFile; fileRef = DDA6B8BC155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.m */; };
DDC4BED5152E3BD700089409 /* RMInteractiveSource.h in Headers */ = {isa = PBXBuildFile; fileRef = DDC4BED3152E3BD700089409 /* RMInteractiveSource.h */; };
DDC4BEE3152E3DE700089409 /* GRMustache.h in Headers */ = {isa = PBXBuildFile; fileRef = DDC4BED8152E3DE700089409 /* GRMustache.h */; };
DDC4BEE4152E3DE700089409 /* GRMustacheAvailabilityMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = DDC4BED9152E3DE700089409 /* GRMustacheAvailabilityMacros.h */; };
... ... @@ -332,6 +334,12 @@
DD8FD7691559EE120044D96F /* TrackingDotHalo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "TrackingDotHalo@2x.png"; path = "Resources/TrackingDotHalo@2x.png"; sourceTree = "<group>"; };
DD8FD76C1559EE120044D96F /* TrackingDotHalo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = TrackingDotHalo.png; path = Resources/TrackingDotHalo.png; sourceTree = "<group>"; };
DD96559015264C810008517A /* RMMapBoxSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMMapBoxSource.h; sourceTree = "<group>"; };
DDA6B8BB155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMUserTrackingBarButtonItem.h; sourceTree = "<group>"; };
DDA6B8BC155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMUserTrackingBarButtonItem.m; sourceTree = "<group>"; };
DDA6B8C0155CAB9A003DB5D8 /* TrackingLocation.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = TrackingLocation.png; path = Resources/TrackingLocation.png; sourceTree = "<group>"; };
DDA6B8C1155CAB9A003DB5D8 /* TrackingLocation@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "TrackingLocation@2x.png"; path = "Resources/TrackingLocation@2x.png"; sourceTree = "<group>"; };
DDA6B8C2155CAB9A003DB5D8 /* TrackingHeading.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = TrackingHeading.png; path = Resources/TrackingHeading.png; sourceTree = "<group>"; };
DDA6B8C3155CAB9A003DB5D8 /* TrackingHeading@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "TrackingHeading@2x.png"; path = "Resources/TrackingHeading@2x.png"; sourceTree = "<group>"; };
DDC4BED3152E3BD700089409 /* RMInteractiveSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RMInteractiveSource.h; sourceTree = "<group>"; };
DDC4BED4152E3BD700089409 /* RMInteractiveSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RMInteractiveSource.m; sourceTree = "<group>"; };
DDC4BED8152E3DE700089409 /* GRMustache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GRMustache.h; sourceTree = "<group>"; };
... ... @@ -674,6 +682,8 @@
children = (
DD8FD7521559E4A40044D96F /* RMUserLocation.h */,
DD8FD7531559E4A40044D96F /* RMUserLocation.m */,
DDA6B8BB155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.h */,
DDA6B8BC155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.m */,
DD8FD7581559EDA80044D96F /* Resources */,
);
name = "User Location";
... ... @@ -688,6 +698,10 @@
DD8FD7661559EE120044D96F /* TrackingDot@2x.png */,
DD8FD76C1559EE120044D96F /* TrackingDotHalo.png */,
DD8FD7691559EE120044D96F /* TrackingDotHalo@2x.png */,
DDA6B8C2155CAB9A003DB5D8 /* TrackingHeading.png */,
DDA6B8C3155CAB9A003DB5D8 /* TrackingHeading@2x.png */,
DDA6B8C0155CAB9A003DB5D8 /* TrackingLocation.png */,
DDA6B8C1155CAB9A003DB5D8 /* TrackingLocation@2x.png */,
);
name = Resources;
sourceTree = "<group>";
... ... @@ -791,6 +805,7 @@
DD6380DD152E72880074E66E /* RMMapBoxSource.h in Headers */,
DD103E241540E3CF00AA65DD /* RMCompositeSource.h in Headers */,
DD8FD7541559E4A40044D96F /* RMUserLocation.h in Headers */,
DDA6B8BD155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
... ... @@ -1011,6 +1026,7 @@
DDC4BEF2152E3FAE00089409 /* RMInteractiveSource.m in Sources */,
DD103E251540E3CF00AA65DD /* RMCompositeSource.m in Sources */,
DD8FD7551559E4A40044D96F /* RMUserLocation.m in Sources */,
DDA6B8BE155CAB67003DB5D8 /* RMUserTrackingBarButtonItem.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
... ...