├── .gitignore ├── DBMapSelectorViewController.podspec ├── Example ├── Classes │ ├── ViewController.h │ └── ViewController.m ├── DBMapSelectorViewControllerExample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── DBMapSelectorViewControllerExample │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Info.plist │ └── main.m └── Resources │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json │ └── Screenshot.jpg ├── LICENSE ├── README.md └── Source ├── DBMapSelectorGestureRecognizer.h ├── DBMapSelectorGestureRecognizer.m ├── DBMapSelectorManager.h ├── DBMapSelectorManager.m ├── MapSelectorAnnotation ├── DBMapSelectorAnnotation.h └── DBMapSelectorAnnotation.m └── MapSelectorOverlay ├── DBMapSelectorOverlay.h ├── DBMapSelectorOverlay.m ├── DBMapSelectorOverlayRenderer.h └── DBMapSelectorOverlayRenderer.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | #Pods/ 27 | -------------------------------------------------------------------------------- /DBMapSelectorViewController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'DBMapSelectorViewController' 3 | s.version = '1.2.2' 4 | s.authors = { 'Denis Bogatyrev' => 'denis.bogatyrev@gmail.com' } 5 | s.summary = 'This component allows you to select circular map region from the MKMapView' 6 | s.homepage = 'https://github.com/d0ping/DBMapSelectorViewController' 7 | s.license = { :type => 'MIT' } 8 | s.requires_arc = true 9 | s.platform = :ios, '6.0' 10 | s.source = { :git => 'https://github.com/d0ping/DBMapSelectorViewController.git', :tag => "#{s.version}" } 11 | s.source_files = 'Source/**/*.{h,m}' 12 | s.public_header_files = 'Source/**/*.h' 13 | end 14 | -------------------------------------------------------------------------------- /Example/Classes/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // DBMapSelectorViewControllerExample 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // Copyright (c) 2015 Denis Bogatyrev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface ViewController : UIViewController 13 | 14 | @property (nonatomic, weak) IBOutlet MKMapView *mapView; 15 | 16 | @property (nonatomic, weak) IBOutlet UISwitch *hiddenSwitch; 17 | 18 | @property (nonatomic, weak) IBOutlet UILabel *coordinateLabel; 19 | @property (nonatomic, weak) IBOutlet UILabel *radiusLabel; 20 | 21 | @property (nonatomic, weak) IBOutlet UISegmentedControl *editingTypeSegmentedControl; 22 | @property (nonatomic, weak) IBOutlet UISegmentedControl *fillingModeSegmentedControl; 23 | 24 | @property (nonatomic, weak) IBOutlet UITextField *fillColorTextField; 25 | @property (nonatomic, weak) IBOutlet UITextField *strokeColorTextField; 26 | 27 | @end 28 | 29 | -------------------------------------------------------------------------------- /Example/Classes/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // DBMapSelectorViewControllerExample 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // Copyright (c) 2015 Denis Bogatyrev. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "DBMapSelectorManager.h" 11 | 12 | @interface ViewController () { 13 | NSDictionary *_fillColorDict; 14 | NSDictionary *_strokeColorDict; 15 | UIPickerView *_fillColorPickerView; 16 | UIPickerView *_strokeColorPickerView; 17 | } 18 | 19 | @property (nonatomic, strong) DBMapSelectorManager *mapSelectorManager; 20 | 21 | @end 22 | 23 | @implementation ViewController 24 | 25 | - (DBMapSelectorManager *)mapSelectorManager { 26 | if (nil == _mapSelectorManager) { 27 | _mapSelectorManager = [[DBMapSelectorManager alloc] initWithMapView:self.mapView]; 28 | _mapSelectorManager.delegate = self; 29 | } 30 | return _mapSelectorManager; 31 | } 32 | 33 | #pragma mark - Source 34 | 35 | - (void)viewDidLoad { 36 | [super viewDidLoad]; 37 | 38 | _mapView.showsUserLocation = YES; 39 | 40 | // Set map selector settings 41 | self.mapSelectorManager.circleCoordinate = CLLocationCoordinate2DMake(55.75399400, 37.62209300); 42 | self.mapSelectorManager.circleRadius = 3000; 43 | self.mapSelectorManager.circleRadiusMax = 25000; 44 | [self.mapSelectorManager applySelectorSettings]; 45 | 46 | _fillColorDict = @{@"Orange": [UIColor orangeColor], @"Green": [UIColor greenColor], @"Pure": [UIColor purpleColor], @"Cyan": [UIColor cyanColor], @"Yellow": [UIColor yellowColor], @"Magenta": [UIColor magentaColor]}; 47 | _strokeColorDict = @{@"Dark Gray": [UIColor darkGrayColor], @"Black": [UIColor blackColor], @"Brown": [UIColor brownColor], @"Red": [UIColor redColor], @"Blue": [UIColor blueColor]}; 48 | 49 | _fillColorPickerView = [[UIPickerView alloc] init]; 50 | _fillColorPickerView.delegate = self; 51 | _fillColorPickerView.dataSource = self; 52 | _fillColorPickerView.showsSelectionIndicator = YES; 53 | 54 | _strokeColorPickerView = [[UIPickerView alloc] init]; 55 | _strokeColorPickerView.delegate = self; 56 | _strokeColorPickerView.dataSource = self; 57 | _strokeColorPickerView.showsSelectionIndicator = YES; 58 | 59 | NSString *fillColorKey = @"Orange"; 60 | _fillColorTextField.text = fillColorKey; 61 | self.mapSelectorManager.fillColor = _fillColorDict[fillColorKey]; 62 | 63 | NSString *strokeColorKey = @"Dark Gray"; 64 | _strokeColorTextField.text = strokeColorKey; 65 | self.mapSelectorManager.strokeColor = _strokeColorDict[strokeColorKey]; 66 | 67 | UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(inputAccessoryViewDidFinish)]; 68 | UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0,0, 320, 44)]; 69 | [toolbar setItems:@[doneButton] animated:NO]; 70 | 71 | _fillColorTextField.inputView = _fillColorPickerView; 72 | _fillColorTextField.inputAccessoryView = toolbar; 73 | 74 | _strokeColorTextField.inputView = _strokeColorPickerView; 75 | _strokeColorTextField.inputAccessoryView = toolbar; 76 | 77 | } 78 | 79 | - (void)inputAccessoryViewDidFinish { 80 | [_fillColorTextField resignFirstResponder]; 81 | [_strokeColorTextField resignFirstResponder]; 82 | } 83 | 84 | #pragma mark - Actions 85 | 86 | - (IBAction)editingTypeSegmentedControlValueDidChange:(UISegmentedControl *)sender { 87 | self.mapSelectorManager.editingType = sender.selectedSegmentIndex; 88 | } 89 | 90 | - (IBAction)fillingModeSegmentedControlValueDidChange:(UISegmentedControl *)sender { 91 | self.mapSelectorManager.fillInside = (sender.selectedSegmentIndex == 0); 92 | } 93 | 94 | - (IBAction)hiddenSwitchValueDidChange:(UISwitch *)sender { 95 | self.mapSelectorManager.hidden = !sender.on; 96 | } 97 | 98 | #pragma mark - DBMapSelectorManager Delegate 99 | 100 | - (void)mapSelectorManager:(DBMapSelectorManager *)mapSelectorManager didChangeCoordinate:(CLLocationCoordinate2D)coordinate { 101 | _coordinateLabel.text = [NSString stringWithFormat:@"Coordinate = {%.5f, %.5f}", coordinate.latitude, coordinate.longitude]; 102 | } 103 | 104 | - (void)mapSelectorManager:(DBMapSelectorManager *)mapSelectorManager didChangeRadius:(CLLocationDistance)radius { 105 | NSString *radiusStr = (radius >= 1000) ? [NSString stringWithFormat:@"%.1f km", radius * .001f] : [NSString stringWithFormat:@"%.0f m", radius]; 106 | _radiusLabel.text = [@"Radius = " stringByAppendingString:radiusStr]; 107 | } 108 | 109 | #pragma mark - UIPickerView Delegate && DataSource 110 | 111 | - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { 112 | return 1; 113 | } 114 | 115 | - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { 116 | NSDictionary *dict = [pickerView isEqual:_fillColorPickerView] ? _fillColorDict : _strokeColorDict; 117 | return dict.count; 118 | } 119 | 120 | - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { 121 | NSDictionary *dict = [pickerView isEqual:_fillColorPickerView] ? _fillColorDict : _strokeColorDict; 122 | return dict.allKeys[row]; 123 | } 124 | 125 | - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { 126 | NSDictionary *dict = [pickerView isEqual:_fillColorPickerView] ? _fillColorDict : _strokeColorDict; 127 | NSString *colorKey = dict.allKeys[row]; 128 | if ([pickerView isEqual:_fillColorPickerView]) { 129 | self.fillColorTextField.text = colorKey; 130 | self.mapSelectorManager.fillColor = _fillColorDict[colorKey]; 131 | } else if ([pickerView isEqual:_strokeColorPickerView]) { 132 | self.strokeColorTextField.text = colorKey; 133 | self.mapSelectorManager.strokeColor = _strokeColorDict[colorKey]; 134 | } 135 | } 136 | 137 | #pragma mark - MKMapViewDelegate 138 | 139 | - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation { 140 | return [self.mapSelectorManager mapView:mapView viewForAnnotation:annotation]; 141 | } 142 | 143 | - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState { 144 | [self.mapSelectorManager mapView:mapView annotationView:annotationView didChangeDragState:newState fromOldState:oldState]; 145 | } 146 | 147 | - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id )overlay { 148 | return [self.mapSelectorManager mapView:mapView rendererForOverlay:overlay]; 149 | } 150 | 151 | - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { 152 | [self.mapSelectorManager mapView:mapView regionDidChangeAnimated:animated]; 153 | } 154 | 155 | @end 156 | -------------------------------------------------------------------------------- /Example/DBMapSelectorViewControllerExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A40D268C1AE2967B00A511E0 /* DBMapSelectorAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = A40D268B1AE2967B00A511E0 /* DBMapSelectorAnnotation.m */; }; 11 | C3FDCD671AC57B350053FDC7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FDCD661AC57B350053FDC7 /* main.m */; }; 12 | C3FDCD6A1AC57B350053FDC7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FDCD691AC57B350053FDC7 /* AppDelegate.m */; }; 13 | C3FDCD701AC57B350053FDC7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C3FDCD6E1AC57B350053FDC7 /* Main.storyboard */; }; 14 | C3FDCD751AC57B350053FDC7 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = C3FDCD731AC57B350053FDC7 /* LaunchScreen.xib */; }; 15 | C3FDCD8F1AC57C2B0053FDC7 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FDCD8C1AC57C2B0053FDC7 /* ViewController.m */; }; 16 | C3FDCD901AC57C2B0053FDC7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C3FDCD8E1AC57C2B0053FDC7 /* Images.xcassets */; }; 17 | C3FDCD921AC57C710053FDC7 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3FDCD911AC57C710053FDC7 /* MapKit.framework */; }; 18 | C3FDCDA11AC581DE0053FDC7 /* DBMapSelectorOverlay.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FDCDA01AC581DE0053FDC7 /* DBMapSelectorOverlay.m */; }; 19 | C3FDCDA41AC5830E0053FDC7 /* DBMapSelectorOverlayRenderer.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FDCDA31AC5830E0053FDC7 /* DBMapSelectorOverlayRenderer.m */; }; 20 | C3FDCDA91AC6A2060053FDC7 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3FDCDA81AC6A2060053FDC7 /* CoreLocation.framework */; }; 21 | C3FDCDAC1AC6EF450053FDC7 /* DBMapSelectorGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = C3FDCDAB1AC6EF450053FDC7 /* DBMapSelectorGestureRecognizer.m */; }; 22 | F7DDE3211AD7AE0D00A67502 /* DBMapSelectorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F7DDE3201AD7AE0D00A67502 /* DBMapSelectorManager.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXFileReference section */ 26 | A40D268A1AE2967B00A511E0 /* DBMapSelectorAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBMapSelectorAnnotation.h; sourceTree = ""; }; 27 | A40D268B1AE2967B00A511E0 /* DBMapSelectorAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBMapSelectorAnnotation.m; sourceTree = ""; }; 28 | C3FDCD611AC57B350053FDC7 /* DBMapSelectorViewControllerExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DBMapSelectorViewControllerExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | C3FDCD651AC57B350053FDC7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 30 | C3FDCD661AC57B350053FDC7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 31 | C3FDCD681AC57B350053FDC7 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 32 | C3FDCD691AC57B350053FDC7 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 33 | C3FDCD6F1AC57B350053FDC7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 34 | C3FDCD741AC57B350053FDC7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 35 | C3FDCD8B1AC57C2B0053FDC7 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 36 | C3FDCD8C1AC57C2B0053FDC7 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 37 | C3FDCD8E1AC57C2B0053FDC7 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 38 | C3FDCD911AC57C710053FDC7 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; 39 | C3FDCD9F1AC581DE0053FDC7 /* DBMapSelectorOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBMapSelectorOverlay.h; sourceTree = ""; }; 40 | C3FDCDA01AC581DE0053FDC7 /* DBMapSelectorOverlay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBMapSelectorOverlay.m; sourceTree = ""; }; 41 | C3FDCDA21AC5830E0053FDC7 /* DBMapSelectorOverlayRenderer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DBMapSelectorOverlayRenderer.h; sourceTree = ""; }; 42 | C3FDCDA31AC5830E0053FDC7 /* DBMapSelectorOverlayRenderer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DBMapSelectorOverlayRenderer.m; sourceTree = ""; }; 43 | C3FDCDA81AC6A2060053FDC7 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = System/Library/Frameworks/CoreLocation.framework; sourceTree = SDKROOT; }; 44 | C3FDCDAA1AC6EF450053FDC7 /* DBMapSelectorGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DBMapSelectorGestureRecognizer.h; path = ../../Source/DBMapSelectorGestureRecognizer.h; sourceTree = ""; }; 45 | C3FDCDAB1AC6EF450053FDC7 /* DBMapSelectorGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DBMapSelectorGestureRecognizer.m; path = ../../Source/DBMapSelectorGestureRecognizer.m; sourceTree = ""; }; 46 | F7DDE31F1AD7AE0D00A67502 /* DBMapSelectorManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DBMapSelectorManager.h; path = ../../Source/DBMapSelectorManager.h; sourceTree = ""; }; 47 | F7DDE3201AD7AE0D00A67502 /* DBMapSelectorManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DBMapSelectorManager.m; path = ../../Source/DBMapSelectorManager.m; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | C3FDCD5E1AC57B350053FDC7 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | C3FDCDA91AC6A2060053FDC7 /* CoreLocation.framework in Frameworks */, 56 | C3FDCD921AC57C710053FDC7 /* MapKit.framework in Frameworks */, 57 | ); 58 | runOnlyForDeploymentPostprocessing = 0; 59 | }; 60 | /* End PBXFrameworksBuildPhase section */ 61 | 62 | /* Begin PBXGroup section */ 63 | A40D26891AE2967B00A511E0 /* MapSelectorAnnotation */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | A40D268A1AE2967B00A511E0 /* DBMapSelectorAnnotation.h */, 67 | A40D268B1AE2967B00A511E0 /* DBMapSelectorAnnotation.m */, 68 | ); 69 | name = MapSelectorAnnotation; 70 | path = ../../Source/MapSelectorAnnotation; 71 | sourceTree = ""; 72 | }; 73 | C3FDCD581AC57B350053FDC7 = { 74 | isa = PBXGroup; 75 | children = ( 76 | C3FDCDA81AC6A2060053FDC7 /* CoreLocation.framework */, 77 | C3FDCD911AC57C710053FDC7 /* MapKit.framework */, 78 | C3FDCD631AC57B350053FDC7 /* DBMapSelectorViewControllerExample */, 79 | C3FDCD8A1AC57C2B0053FDC7 /* Classes */, 80 | C3FDCD8D1AC57C2B0053FDC7 /* Resources */, 81 | C3FDCD621AC57B350053FDC7 /* Products */, 82 | ); 83 | sourceTree = ""; 84 | }; 85 | C3FDCD621AC57B350053FDC7 /* Products */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | C3FDCD611AC57B350053FDC7 /* DBMapSelectorViewControllerExample.app */, 89 | ); 90 | name = Products; 91 | sourceTree = ""; 92 | }; 93 | C3FDCD631AC57B350053FDC7 /* DBMapSelectorViewControllerExample */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | C3FDCD681AC57B350053FDC7 /* AppDelegate.h */, 97 | C3FDCD691AC57B350053FDC7 /* AppDelegate.m */, 98 | C3FDCD731AC57B350053FDC7 /* LaunchScreen.xib */, 99 | C3FDCD641AC57B350053FDC7 /* Supporting Files */, 100 | ); 101 | path = DBMapSelectorViewControllerExample; 102 | sourceTree = ""; 103 | }; 104 | C3FDCD641AC57B350053FDC7 /* Supporting Files */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | C3FDCD651AC57B350053FDC7 /* Info.plist */, 108 | C3FDCD661AC57B350053FDC7 /* main.m */, 109 | ); 110 | name = "Supporting Files"; 111 | sourceTree = ""; 112 | }; 113 | C3FDCD8A1AC57C2B0053FDC7 /* Classes */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | C3FDCD931AC57C860053FDC7 /* DBMapSelectorViewController */, 117 | C3FDCD6E1AC57B350053FDC7 /* Main.storyboard */, 118 | C3FDCD8B1AC57C2B0053FDC7 /* ViewController.h */, 119 | C3FDCD8C1AC57C2B0053FDC7 /* ViewController.m */, 120 | ); 121 | path = Classes; 122 | sourceTree = ""; 123 | }; 124 | C3FDCD8D1AC57C2B0053FDC7 /* Resources */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | C3FDCD8E1AC57C2B0053FDC7 /* Images.xcassets */, 128 | ); 129 | path = Resources; 130 | sourceTree = ""; 131 | }; 132 | C3FDCD931AC57C860053FDC7 /* DBMapSelectorViewController */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | F7DDE31F1AD7AE0D00A67502 /* DBMapSelectorManager.h */, 136 | F7DDE3201AD7AE0D00A67502 /* DBMapSelectorManager.m */, 137 | C3FDCDAA1AC6EF450053FDC7 /* DBMapSelectorGestureRecognizer.h */, 138 | C3FDCDAB1AC6EF450053FDC7 /* DBMapSelectorGestureRecognizer.m */, 139 | A40D26891AE2967B00A511E0 /* MapSelectorAnnotation */, 140 | C3FDCD9B1AC5805B0053FDC7 /* MapSelectorOverlay */, 141 | ); 142 | name = DBMapSelectorViewController; 143 | sourceTree = ""; 144 | }; 145 | C3FDCD9B1AC5805B0053FDC7 /* MapSelectorOverlay */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | C3FDCD9F1AC581DE0053FDC7 /* DBMapSelectorOverlay.h */, 149 | C3FDCDA01AC581DE0053FDC7 /* DBMapSelectorOverlay.m */, 150 | C3FDCDA21AC5830E0053FDC7 /* DBMapSelectorOverlayRenderer.h */, 151 | C3FDCDA31AC5830E0053FDC7 /* DBMapSelectorOverlayRenderer.m */, 152 | ); 153 | name = MapSelectorOverlay; 154 | path = ../../Source/MapSelectorOverlay; 155 | sourceTree = ""; 156 | }; 157 | /* End PBXGroup section */ 158 | 159 | /* Begin PBXNativeTarget section */ 160 | C3FDCD601AC57B350053FDC7 /* DBMapSelectorViewControllerExample */ = { 161 | isa = PBXNativeTarget; 162 | buildConfigurationList = C3FDCD841AC57B350053FDC7 /* Build configuration list for PBXNativeTarget "DBMapSelectorViewControllerExample" */; 163 | buildPhases = ( 164 | C3FDCD5D1AC57B350053FDC7 /* Sources */, 165 | C3FDCD5E1AC57B350053FDC7 /* Frameworks */, 166 | C3FDCD5F1AC57B350053FDC7 /* Resources */, 167 | ); 168 | buildRules = ( 169 | ); 170 | dependencies = ( 171 | ); 172 | name = DBMapSelectorViewControllerExample; 173 | productName = DBMapSelectorViewControllerExample; 174 | productReference = C3FDCD611AC57B350053FDC7 /* DBMapSelectorViewControllerExample.app */; 175 | productType = "com.apple.product-type.application"; 176 | }; 177 | /* End PBXNativeTarget section */ 178 | 179 | /* Begin PBXProject section */ 180 | C3FDCD591AC57B350053FDC7 /* Project object */ = { 181 | isa = PBXProject; 182 | attributes = { 183 | LastUpgradeCheck = 0620; 184 | ORGANIZATIONNAME = "Denis Bogatyrev"; 185 | TargetAttributes = { 186 | C3FDCD601AC57B350053FDC7 = { 187 | CreatedOnToolsVersion = 6.2; 188 | }; 189 | }; 190 | }; 191 | buildConfigurationList = C3FDCD5C1AC57B350053FDC7 /* Build configuration list for PBXProject "DBMapSelectorViewControllerExample" */; 192 | compatibilityVersion = "Xcode 3.2"; 193 | developmentRegion = English; 194 | hasScannedForEncodings = 0; 195 | knownRegions = ( 196 | en, 197 | Base, 198 | ); 199 | mainGroup = C3FDCD581AC57B350053FDC7; 200 | productRefGroup = C3FDCD621AC57B350053FDC7 /* Products */; 201 | projectDirPath = ""; 202 | projectRoot = ""; 203 | targets = ( 204 | C3FDCD601AC57B350053FDC7 /* DBMapSelectorViewControllerExample */, 205 | ); 206 | }; 207 | /* End PBXProject section */ 208 | 209 | /* Begin PBXResourcesBuildPhase section */ 210 | C3FDCD5F1AC57B350053FDC7 /* Resources */ = { 211 | isa = PBXResourcesBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | C3FDCD901AC57C2B0053FDC7 /* Images.xcassets in Resources */, 215 | C3FDCD701AC57B350053FDC7 /* Main.storyboard in Resources */, 216 | C3FDCD751AC57B350053FDC7 /* LaunchScreen.xib in Resources */, 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | }; 220 | /* End PBXResourcesBuildPhase section */ 221 | 222 | /* Begin PBXSourcesBuildPhase section */ 223 | C3FDCD5D1AC57B350053FDC7 /* Sources */ = { 224 | isa = PBXSourcesBuildPhase; 225 | buildActionMask = 2147483647; 226 | files = ( 227 | F7DDE3211AD7AE0D00A67502 /* DBMapSelectorManager.m in Sources */, 228 | C3FDCD8F1AC57C2B0053FDC7 /* ViewController.m in Sources */, 229 | C3FDCDA41AC5830E0053FDC7 /* DBMapSelectorOverlayRenderer.m in Sources */, 230 | C3FDCDA11AC581DE0053FDC7 /* DBMapSelectorOverlay.m in Sources */, 231 | A40D268C1AE2967B00A511E0 /* DBMapSelectorAnnotation.m in Sources */, 232 | C3FDCD6A1AC57B350053FDC7 /* AppDelegate.m in Sources */, 233 | C3FDCDAC1AC6EF450053FDC7 /* DBMapSelectorGestureRecognizer.m in Sources */, 234 | C3FDCD671AC57B350053FDC7 /* main.m in Sources */, 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | }; 238 | /* End PBXSourcesBuildPhase section */ 239 | 240 | /* Begin PBXVariantGroup section */ 241 | C3FDCD6E1AC57B350053FDC7 /* Main.storyboard */ = { 242 | isa = PBXVariantGroup; 243 | children = ( 244 | C3FDCD6F1AC57B350053FDC7 /* Base */, 245 | ); 246 | name = Main.storyboard; 247 | path = ../DBMapSelectorViewControllerExample; 248 | sourceTree = ""; 249 | }; 250 | C3FDCD731AC57B350053FDC7 /* LaunchScreen.xib */ = { 251 | isa = PBXVariantGroup; 252 | children = ( 253 | C3FDCD741AC57B350053FDC7 /* Base */, 254 | ); 255 | name = LaunchScreen.xib; 256 | sourceTree = ""; 257 | }; 258 | /* End PBXVariantGroup section */ 259 | 260 | /* Begin XCBuildConfiguration section */ 261 | C3FDCD821AC57B350053FDC7 /* Debug */ = { 262 | isa = XCBuildConfiguration; 263 | buildSettings = { 264 | ALWAYS_SEARCH_USER_PATHS = NO; 265 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 266 | CLANG_CXX_LIBRARY = "libc++"; 267 | CLANG_ENABLE_MODULES = YES; 268 | CLANG_ENABLE_OBJC_ARC = YES; 269 | CLANG_WARN_BOOL_CONVERSION = YES; 270 | CLANG_WARN_CONSTANT_CONVERSION = YES; 271 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 272 | CLANG_WARN_EMPTY_BODY = YES; 273 | CLANG_WARN_ENUM_CONVERSION = YES; 274 | CLANG_WARN_INT_CONVERSION = YES; 275 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 276 | CLANG_WARN_UNREACHABLE_CODE = YES; 277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 278 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 279 | COPY_PHASE_STRIP = NO; 280 | ENABLE_STRICT_OBJC_MSGSEND = YES; 281 | GCC_C_LANGUAGE_STANDARD = gnu99; 282 | GCC_DYNAMIC_NO_PIC = NO; 283 | GCC_OPTIMIZATION_LEVEL = 0; 284 | GCC_PREPROCESSOR_DEFINITIONS = ( 285 | "DEBUG=1", 286 | "$(inherited)", 287 | ); 288 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 291 | GCC_WARN_UNDECLARED_SELECTOR = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 293 | GCC_WARN_UNUSED_FUNCTION = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 296 | MTL_ENABLE_DEBUG_INFO = YES; 297 | ONLY_ACTIVE_ARCH = YES; 298 | SDKROOT = iphoneos; 299 | TARGETED_DEVICE_FAMILY = "1,2"; 300 | }; 301 | name = Debug; 302 | }; 303 | C3FDCD831AC57B350053FDC7 /* Release */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ALWAYS_SEARCH_USER_PATHS = NO; 307 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 308 | CLANG_CXX_LIBRARY = "libc++"; 309 | CLANG_ENABLE_MODULES = YES; 310 | CLANG_ENABLE_OBJC_ARC = YES; 311 | CLANG_WARN_BOOL_CONVERSION = YES; 312 | CLANG_WARN_CONSTANT_CONVERSION = YES; 313 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 314 | CLANG_WARN_EMPTY_BODY = YES; 315 | CLANG_WARN_ENUM_CONVERSION = YES; 316 | CLANG_WARN_INT_CONVERSION = YES; 317 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 318 | CLANG_WARN_UNREACHABLE_CODE = YES; 319 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 320 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 321 | COPY_PHASE_STRIP = NO; 322 | ENABLE_NS_ASSERTIONS = NO; 323 | ENABLE_STRICT_OBJC_MSGSEND = YES; 324 | GCC_C_LANGUAGE_STANDARD = gnu99; 325 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 326 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 327 | GCC_WARN_UNDECLARED_SELECTOR = YES; 328 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 329 | GCC_WARN_UNUSED_FUNCTION = YES; 330 | GCC_WARN_UNUSED_VARIABLE = YES; 331 | IPHONEOS_DEPLOYMENT_TARGET = 6.0; 332 | MTL_ENABLE_DEBUG_INFO = NO; 333 | SDKROOT = iphoneos; 334 | TARGETED_DEVICE_FAMILY = "1,2"; 335 | VALIDATE_PRODUCT = YES; 336 | }; 337 | name = Release; 338 | }; 339 | C3FDCD851AC57B350053FDC7 /* Debug */ = { 340 | isa = XCBuildConfiguration; 341 | buildSettings = { 342 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 343 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 344 | INFOPLIST_FILE = DBMapSelectorViewControllerExample/Info.plist; 345 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 346 | PRODUCT_NAME = "$(TARGET_NAME)"; 347 | }; 348 | name = Debug; 349 | }; 350 | C3FDCD861AC57B350053FDC7 /* Release */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 354 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 355 | INFOPLIST_FILE = DBMapSelectorViewControllerExample/Info.plist; 356 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 357 | PRODUCT_NAME = "$(TARGET_NAME)"; 358 | }; 359 | name = Release; 360 | }; 361 | /* End XCBuildConfiguration section */ 362 | 363 | /* Begin XCConfigurationList section */ 364 | C3FDCD5C1AC57B350053FDC7 /* Build configuration list for PBXProject "DBMapSelectorViewControllerExample" */ = { 365 | isa = XCConfigurationList; 366 | buildConfigurations = ( 367 | C3FDCD821AC57B350053FDC7 /* Debug */, 368 | C3FDCD831AC57B350053FDC7 /* Release */, 369 | ); 370 | defaultConfigurationIsVisible = 0; 371 | defaultConfigurationName = Release; 372 | }; 373 | C3FDCD841AC57B350053FDC7 /* Build configuration list for PBXNativeTarget "DBMapSelectorViewControllerExample" */ = { 374 | isa = XCConfigurationList; 375 | buildConfigurations = ( 376 | C3FDCD851AC57B350053FDC7 /* Debug */, 377 | C3FDCD861AC57B350053FDC7 /* Release */, 378 | ); 379 | defaultConfigurationIsVisible = 0; 380 | defaultConfigurationName = Release; 381 | }; 382 | /* End XCConfigurationList section */ 383 | }; 384 | rootObject = C3FDCD591AC57B350053FDC7 /* Project object */; 385 | } 386 | -------------------------------------------------------------------------------- /Example/DBMapSelectorViewControllerExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/DBMapSelectorViewControllerExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // DBMapSelectorViewControllerExample 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // Copyright (c) 2015 Denis Bogatyrev. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Example/DBMapSelectorViewControllerExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // DBMapSelectorViewControllerExample 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // Copyright (c) 2015 Denis Bogatyrev. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Example/DBMapSelectorViewControllerExample/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Example/DBMapSelectorViewControllerExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 56 | 65 | 74 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /Example/DBMapSelectorViewControllerExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | DB.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.2.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Example/DBMapSelectorViewControllerExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // DBMapSelectorViewControllerExample 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // Copyright (c) 2015 Denis Bogatyrev. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/Resources/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "83.5x83.5", 66 | "scale" : "2x" 67 | } 68 | ], 69 | "info" : { 70 | "version" : 1, 71 | "author" : "xcode" 72 | } 73 | } -------------------------------------------------------------------------------- /Example/Resources/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "1x", 6 | "orientation" : "portrait" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "2x", 11 | "orientation" : "portrait" 12 | }, 13 | { 14 | "orientation" : "portrait", 15 | "idiom" : "iphone", 16 | "subtype" : "retina4", 17 | "scale" : "2x" 18 | }, 19 | { 20 | "orientation" : "portrait", 21 | "idiom" : "iphone", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "2x" 24 | }, 25 | { 26 | "orientation" : "portrait", 27 | "idiom" : "iphone", 28 | "minimum-system-version" : "7.0", 29 | "subtype" : "retina4", 30 | "scale" : "2x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "to-status-bar", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "orientation" : "portrait", 40 | "idiom" : "ipad", 41 | "extent" : "to-status-bar", 42 | "scale" : "2x" 43 | }, 44 | { 45 | "orientation" : "landscape", 46 | "idiom" : "ipad", 47 | "extent" : "to-status-bar", 48 | "scale" : "1x" 49 | }, 50 | { 51 | "orientation" : "landscape", 52 | "idiom" : "ipad", 53 | "extent" : "to-status-bar", 54 | "scale" : "2x" 55 | }, 56 | { 57 | "orientation" : "portrait", 58 | "idiom" : "ipad", 59 | "minimum-system-version" : "7.0", 60 | "extent" : "full-screen", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "orientation" : "portrait", 65 | "idiom" : "ipad", 66 | "minimum-system-version" : "7.0", 67 | "extent" : "full-screen", 68 | "scale" : "2x" 69 | }, 70 | { 71 | "orientation" : "landscape", 72 | "idiom" : "ipad", 73 | "minimum-system-version" : "7.0", 74 | "extent" : "full-screen", 75 | "scale" : "1x" 76 | }, 77 | { 78 | "orientation" : "landscape", 79 | "idiom" : "ipad", 80 | "minimum-system-version" : "7.0", 81 | "extent" : "full-screen", 82 | "scale" : "2x" 83 | } 84 | ], 85 | "info" : { 86 | "version" : 1, 87 | "author" : "xcode" 88 | } 89 | } -------------------------------------------------------------------------------- /Example/Resources/Screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/d0ping/DBMapSelectorViewController/a1dea389395c48fdd57769920ba903796e540eba/Example/Resources/Screenshot.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Denis Bogatyrev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DBMapSelectorViewController 2 | [![Version](https://img.shields.io/cocoapods/v/DBMapSelectorViewController.svg?style=flat)](http://cocoadocs.org/docsets/DBMapSelectorViewController) 3 | [![License](https://img.shields.io/cocoapods/l/DBMapSelectorViewController.svg?style=flat)](http://cocoadocs.org/docsets/DBMapSelectorViewController) 4 | [![Platform](https://img.shields.io/cocoapods/p/DBMapSelectorViewController.svg?style=flat)](http://cocoadocs.org/docsets/DBMapSelectorViewController) 5 | ![Language](https://img.shields.io/badge/Language-%20Objective%20C%20-blue.svg) 6 | 7 | This component allows you to select circular map region from the MKMapView. 8 | 9 | ![Screenshot of Example](https://github.com/d0ping/DBMapSelectorViewController/blob/master/Example/Resources/Screenshot.jpg) 10 | 11 | ## Adding to your project 12 | 13 | ### CocoaPods 14 | 15 | To add DBMapSelectorViewController via [CocoaPods](http://cocoapods.org/) into your project: 16 | 17 | 1. Add a pod entry for DBMapSelectorViewController to your Podfile `pod 'DBMapSelectorViewController', '~> 1.2.0'` 18 | 2. Install the pod by running `pod install` 19 | 20 | ### Source Files 21 | 22 | To add DBMapSelectorViewController manually into your project: 23 | 24 | 1. Download the latest code, using `git clone` 25 | 2. Open your project in Xcode, then drag and drop entire contents of the `Source` folder into your project (Make sure to select Copy items when asked if you extracted the code archive outside of your project) 26 | 27 | ## Usage 28 | 29 | To use DBMapSelectorViewController in your project you should perform the following steps: 30 | 31 | 1. Import DBMapSelectorManager.h on your UIViewController subclass. Your class must include MKMapView instance and be his delegate. 32 | 2. In your class implementation create instance of DBMapSelectorManager class. In Initialization method specify mapView instance. Assign your class as the delegate mapSelectorManager if needed. 33 | 3. After initialization, set the initial map selector settings (center and radius) and apply settings. 34 | 4. Forward following messages mapView delegate by the MapSelectorManager instance. 35 | 36 | ```objc 37 | ... 38 | // (1) 39 | #import "DBMapSelectorManager.h" 40 | 41 | @interface ViewController () 42 | @property (nonatomic, strong) DBMapSelectorManager *mapSelectorManager; 43 | @end 44 | 45 | @implementation ViewController 46 | 47 | - (void)viewDidLoad { 48 | [super viewDidLoad]; 49 | 50 | // (2) 51 | self.mapSelectorManager = [[DBMapSelectorManager alloc] initWithMapView:self.mapView]; 52 | self.mapSelectorManager.delegate = self; 53 | 54 | // (3) 55 | self.mapSelectorManager.circleCoordinate = CLLocationCoordinate2DMake(55.75399400, 37.62209300); 56 | self.mapSelectorManager.circleRadius = 3000; 57 | [self.mapSelectorManager applySelectorSettings]; 58 | } 59 | 60 | ... 61 | 62 | // (4) 63 | - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation { 64 | return [self.mapSelectorManager mapView:mapView viewForAnnotation:annotation]; 65 | } 66 | 67 | - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState { 68 | [self.mapSelectorManager mapView:mapView annotationView:annotationView didChangeDragState:newState fromOldState:oldState]; 69 | } 70 | 71 | - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id )overlay { 72 | return [self.mapSelectorManager mapView:mapView rendererForOverlay:overlay]; 73 | } 74 | 75 | - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { 76 | [self.mapSelectorManager mapView:mapView regionDidChangeAnimated:animated]; 77 | } 78 | 79 | @end 80 | ``` 81 | 82 | ### Property list selector 83 | 84 | You can change additional MapSelector properties. Full properties list is shown below: 85 | - `DBMapSelectorEditingType editingType` - Used to specify the selector editing type. Property can equal one of four values: 86 | - `DBMapSelectorEditingTypeFull` allows to edit coordinate and radius, 87 | - `DBMapSelectorEditingTypeCoordinateOnly` allows to edit cooordinate only, 88 | - `DBMapSelectorEditingTypeRadiusOnly` allows to edit radius only, 89 | - `DBMapSelectorEditingTypeNone` read only mode; 90 | - `CLLocationCoordinate2D circleCoordinate` - Used to specify the selector coordinate; 91 | - `CLLocationDistance circleRadius` - Used to specify the selector radius. Default is equal 1000 meter; 92 | - `CLLocationDistance circleRadiusMin` - Used to specify the minimum selector radius. Default is equal 100 meter; 93 | - `CLLocationDistance circleRadiusMax` - Used to specify the maximum selector radius. Default is equal 10000 meter; 94 | - `BOOL hidden` - Used to hide or show selector. Default is NO; 95 | - `BOOL fillInside` - Used to switching between inside or outside filling; 96 | - `UIColor *fillColor` - Used to specify the selector fill color. Color is used to fill the circular map region; 97 | - `UIColor *strokeColor` - Used to specify the selector stroke color. Color is used to delimit the circular map region; 98 | - `CGFloat mapRegionCoef` - Used to specify the magnification factor maps region. This parameter affects display the maps region after changing the selector settings. It is recommended to set a value greater than 1.f; 99 | - `BOOL shouldShowRadiusText` - Indicates whether the radius text should be displayed or not; 100 | - `BOOL shouldLongPressGesture` - It allows to move the selector to a new location via long press gesture. 101 | 102 | ### DBMapSelectorManagerDelegate 103 | 104 | To be able to react when the main properties (coordinate and radius) of the selector will be changed you must become delegate DBMapSelectorManager. DBMapSelectorManagerDelegate protocol you can see here: 105 | 106 | ```objc 107 | @protocol DBMapSelectorManagerDelegate 108 | 109 | @optional 110 | - (void)mapSelectorManager:(DBMapSelectorManager *)mapSelectorManager didChangeCoordinate:(CLLocationCoordinate2D)coordinate; 111 | - (void)mapSelectorManager:(DBMapSelectorManager *)mapSelectorManager didChangeRadius:(CLLocationDistance)radius; 112 | - (void)mapSelectorManagerWillBeginHandlingUserInteraction:(DBMapSelectorManager *)mapSelectorManager; 113 | - (void)mapSelectorManagerDidHandleUserInteraction:(DBMapSelectorManager *)mapSelectorManager; 114 | 115 | @end 116 | ``` 117 | 118 | You can implement these methods in your `MyViewController` class in order to respond to these changes. For example, how it can be implemented in your class: 119 | 120 | ```objc 121 | - (void)mapSelectorManager:(DBMapSelectorManager *)mapSelectorManager didChangeCoordinate:(CLLocationCoordinate2D)coordinate { 122 | _coordinateLabel.text = [NSString stringWithFormat:@"Coordinate = {%.5f, %.5f}", coordinate.latitude, coordinate.longitude]; 123 | } 124 | 125 | - (void)mapSelectorManager:(DBMapSelectorManager *)mapSelectorManager didChangeRadius:(CLLocationDistance)radius { 126 | NSString *radiusStr = (radius >= 1000) ? [NSString stringWithFormat:@"%.1f km", radius * .001f] : [NSString stringWithFormat:@"%.0f m", radius]; 127 | _radiusLabel.text = [@"Radius = " stringByAppendingString:radiusStr]; 128 | } 129 | ``` 130 | ## Version history 131 | 132 | ### 1.2.2 133 | - Improve rendering speed by code optimization 134 | - Other optimizations 135 | 136 | ### 1.2.1 137 | - Added new property `BOOL shouldLongPressGesture`. It allows to move the selector to a new location via long press gesture. 138 | - Added new property `CGFloat mapRegionCoef`. The magnification factor maps region after changing the selector settings. It is recommended to set a value greater than 1.f. 139 | - Improved drawing selector after first display map controller. Fixed problem when sometimes it cuts the circle after first load. 140 | 141 | ### 1.2.0 142 | - The DBMapSelectorViewController was replaced by a DBMapSelectorManager. This change allows the functionality provided by this component to be more easily integrated into existing projects where, for instance, the target view controller already inherits from another custom view controller. (Thank [Marcelo Schroeder](https://github.com/marcelo-schroeder) for giving solution). 143 | - Improved user experience when moving the map selector. 144 | - Fixed bug with incorrect determinating zoom button position in some cases. 145 | 146 | ### 1.1.0 147 | - Added Outside circle mode. 148 | 149 | ## Contact 150 | 151 | Denis Bogatyrev (maintainer) 152 | 153 | - https://github.com/d0ping 154 | - denis.bogatyrev@gmail.com 155 | 156 | ## License 157 | 158 | DBMapSelectorViewController - Copyright (c) 2015 Denis Bogatyrev 159 | 160 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 161 | 162 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 163 | 164 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 165 | -------------------------------------------------------------------------------- /Source/DBMapSelectorGestureRecognizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorGestureRecognizer.h 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 28.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import 23 | 24 | typedef void (^TouchesEventBlock)(NSSet * touches, UIEvent * event); 25 | 26 | @interface DBMapSelectorGestureRecognizer : UIGestureRecognizer { 27 | TouchesEventBlock touchesBeganCallback; 28 | } 29 | 30 | @property(copy) TouchesEventBlock touchesBeganCallback; 31 | @property(copy) TouchesEventBlock touchesMovedCallback; 32 | @property(copy) TouchesEventBlock touchesEndedCallback; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Source/DBMapSelectorGestureRecognizer.m: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorGestureRecognizer.m 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 28.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import "DBMapSelectorGestureRecognizer.h" 23 | 24 | @implementation DBMapSelectorGestureRecognizer 25 | 26 | @synthesize touchesBeganCallback; 27 | @synthesize touchesMovedCallback; 28 | @synthesize touchesEndedCallback; 29 | 30 | - (instancetype)init { 31 | self = [super init]; 32 | if (self) { 33 | self.cancelsTouchesInView = NO; 34 | self.delaysTouchesEnded = NO; 35 | } 36 | return self; 37 | } 38 | 39 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 40 | if (touchesBeganCallback) { 41 | touchesBeganCallback(touches, event); 42 | } 43 | } 44 | 45 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { 46 | } 47 | 48 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 49 | if(touchesEndedCallback) { 50 | touchesEndedCallback(touches, event); 51 | } 52 | } 53 | 54 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 55 | if(touchesMovedCallback) { 56 | touchesMovedCallback(touches, event); 57 | } 58 | } 59 | 60 | - (void)reset { 61 | } 62 | 63 | - (void)ignoreTouch:(UITouch *)touch forEvent:(UIEvent *)event { 64 | } 65 | 66 | - (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer { 67 | return NO; 68 | } 69 | 70 | - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer { 71 | return NO; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /Source/DBMapSelectorManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorManager.h 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import 23 | 24 | @class DBMapSelectorManager; 25 | 26 | /*! @brief Determines how the selector can be edited */ 27 | typedef NS_ENUM(NSInteger, DBMapSelectorEditingType) { 28 | DBMapSelectorEditingTypeFull = 0, 29 | DBMapSelectorEditingTypeCoordinateOnly, 30 | DBMapSelectorEditingTypeRadiusOnly, 31 | DBMapSelectorEditingTypeNone, 32 | }; 33 | 34 | @protocol DBMapSelectorManagerDelegate 35 | 36 | @optional 37 | - (void)mapSelectorManager:(DBMapSelectorManager *)mapSelectorManager didChangeCoordinate:(CLLocationCoordinate2D)coordinate; 38 | - (void)mapSelectorManager:(DBMapSelectorManager *)mapSelectorManager didChangeRadius:(CLLocationDistance)radius; 39 | - (void)mapSelectorManagerWillBeginHandlingUserInteraction:(DBMapSelectorManager *)mapSelectorManager; 40 | - (void)mapSelectorManagerDidHandleUserInteraction:(DBMapSelectorManager *)mapSelectorManager; 41 | 42 | @end 43 | 44 | @class DBMapSelectorOverlay; 45 | @interface DBMapSelectorManager : NSObject 46 | 47 | @property (nonatomic, weak) id delegate; 48 | @property (nonatomic, strong, readonly) MKMapView *mapView; 49 | 50 | /*! 51 | @brief Used to specify the selector editing type 52 | @discussion Property can equal one of four values: 53 | DBMapSelectorEditingTypeFull allows to edit coordinate and radius, 54 | DBMapSelectorEditingTypeCoordinateOnly allows to edit cooordinate only, 55 | DBMapSelectorEditingTypeRadiusOnly allows to edit radius only, 56 | DBMapSelectorEditingTypeNone read only mode. 57 | */ 58 | @property (nonatomic, assign) DBMapSelectorEditingType editingType; 59 | 60 | /*! @brief Used to specify the selector coordinate */ 61 | @property (nonatomic, assign) CLLocationCoordinate2D circleCoordinate; 62 | 63 | /*! @brief Used to specify the selector radius */ 64 | @property (nonatomic, assign) CLLocationDistance circleRadius; // default is equal 1000 meter 65 | 66 | /*! @brief Used to specify the minimum selector radius */ 67 | @property (nonatomic, assign) CLLocationDistance circleRadiusMin; // default is equal 100 meter 68 | 69 | /*! @brief Used to specify the maximum selector radius */ 70 | @property (nonatomic, assign) CLLocationDistance circleRadiusMax; // default is equal 10000 meter 71 | 72 | /*! @brief Used to hide or show selector */ 73 | @property (nonatomic, getter=isHidden) BOOL hidden; // default is NO 74 | 75 | /*! @brief Used to switching between inside or outside filling */ 76 | @property (nonatomic, getter=isFillInside) BOOL fillInside; // default is YES 77 | 78 | /*! 79 | @brief Used to specify the selector fill color 80 | @discussion Color is used to fill the circular map region 81 | */ 82 | @property (nonatomic, strong) UIColor *fillColor; 83 | 84 | /*! 85 | @brief Used to specify the selector stroke color 86 | @discussion Color is used to delimit the circular map region 87 | */ 88 | @property (nonatomic, strong) UIColor *strokeColor; 89 | 90 | /*! 91 | @brief The magnification factor maps region after changing the selector settings 92 | @discussion It is recommended to set a value greater than 1.f 93 | */ 94 | @property (nonatomic, assign) CGFloat mapRegionCoef; // default is equal 2.f 95 | 96 | /*! @brief Indicates whether the radius text should be displayed or not */ 97 | @property (nonatomic) BOOL shouldShowRadiusText; 98 | 99 | /*! @brief It allows to move the selector to a new location via long press gesture */ 100 | @property (nonatomic) BOOL shouldLongPressGesture; // default is NO 101 | 102 | - (instancetype)initWithMapView:(MKMapView *)mapView; 103 | - (void)applySelectorSettings; 104 | 105 | #pragma mark - MKMapViewDelegate (forward when relevant) 106 | 107 | - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation; 108 | - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState; 109 | - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id )overlay; 110 | - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated; 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /Source/DBMapSelectorManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorManager.m 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import "DBMapSelectorGestureRecognizer.h" 23 | 24 | #import "DBMapSelectorAnnotation.h" 25 | #import "DBMapSelectorOverlay.h" 26 | #import "DBMapSelectorOverlayRenderer.h" 27 | #import "DBMapSelectorManager.h" 28 | 29 | 30 | static const NSInteger kDefaultRadius = 1000; 31 | static const NSInteger kDefaultMinDistance = 100; 32 | static const NSInteger kDefaultMaxDistance = 10000; 33 | 34 | @interface DBMapSelectorManager () { 35 | BOOL _isFirstTimeApplySelectorSettings; 36 | UIView *_radiusTouchView; 37 | UILongPressGestureRecognizer *_longPressGestureRecognizer; 38 | } 39 | 40 | @property (strong, nonatomic) DBMapSelectorOverlay *selectorOverlay; 41 | @property (strong, nonatomic) DBMapSelectorOverlayRenderer *selectorOverlayRenderer; 42 | 43 | @property (assign, nonatomic) BOOL mapViewGestureEnabled; 44 | @property (assign, nonatomic) MKMapPoint prevMapPoint; 45 | @property (assign, nonatomic) CLLocationDistance prevRadius; 46 | @property (assign, nonatomic) CGRect radiusTouchRect; 47 | 48 | @end 49 | 50 | @implementation DBMapSelectorManager 51 | 52 | - (instancetype)initWithMapView:(MKMapView *)mapView { 53 | self = [super init]; 54 | if (self) { 55 | _isFirstTimeApplySelectorSettings = YES; 56 | _mapView = mapView; 57 | [self prepareForFirstUse]; 58 | } 59 | return self; 60 | } 61 | 62 | - (void)prepareForFirstUse { 63 | [self selectorSetDefaults]; 64 | 65 | _selectorOverlay = [[DBMapSelectorOverlay alloc] initWithCenterCoordinate:_circleCoordinate radius:_circleRadius]; 66 | 67 | #ifdef DEBUG 68 | _radiusTouchView = [[UIView alloc] initWithFrame:CGRectZero]; 69 | _radiusTouchView.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:.5f]; 70 | _radiusTouchView.userInteractionEnabled = NO; 71 | // [self.mapView addSubview:_radiusTouchView]; 72 | #endif 73 | 74 | _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognizer:)]; 75 | 76 | _mapViewGestureEnabled = YES; 77 | [self.mapView addGestureRecognizer:[self selectorGestureRecognizer]]; 78 | 79 | } 80 | 81 | #pragma mark Defaults 82 | 83 | - (void)selectorSetDefaults { 84 | self.editingType = DBMapSelectorEditingTypeFull; 85 | self.circleRadius = kDefaultRadius; 86 | self.circleRadiusMin = kDefaultMinDistance; 87 | self.circleRadiusMax = kDefaultMaxDistance; 88 | self.hidden = NO; 89 | self.fillInside = YES; 90 | self.shouldShowRadiusText = YES; 91 | self.fillColor = [UIColor orangeColor]; 92 | self.strokeColor = [UIColor darkGrayColor]; 93 | self.mapRegionCoef = 2.f; 94 | } 95 | 96 | - (void)applySelectorSettings { 97 | [self updateMapRegionForMapSelector]; 98 | [self displaySelectorAnnotationIfNeeded]; 99 | [self recalculateRadiusTouchRect]; 100 | if (_isFirstTimeApplySelectorSettings) { 101 | _isFirstTimeApplySelectorSettings = NO; 102 | [self.mapView removeOverlay:_selectorOverlay]; 103 | [self.mapView addOverlay:_selectorOverlay]; 104 | } 105 | } 106 | 107 | #pragma mark - GestureRecognizer 108 | 109 | - (DBMapSelectorGestureRecognizer *)selectorGestureRecognizer { 110 | 111 | __weak typeof(self)weakSelf = self; 112 | DBMapSelectorGestureRecognizer *selectorGestureRecognizer = [[DBMapSelectorGestureRecognizer alloc] init]; 113 | 114 | selectorGestureRecognizer.touchesBeganCallback = ^(NSSet * touches, UIEvent * event) { 115 | UITouch *touch = [touches anyObject]; 116 | CGPoint touchPoint = [touch locationInView:weakSelf.mapView]; 117 | // NSLog(@"---- %@", CGRectContainsPoint(weakSelf.selectorRadiusRect, p) ? @"Y" : @"N"); 118 | 119 | CLLocationCoordinate2D coord = [weakSelf.mapView convertPoint:touchPoint toCoordinateFromView:weakSelf.mapView]; 120 | MKMapPoint mapPoint = MKMapPointForCoordinate(coord); 121 | 122 | if (CGRectContainsPoint(weakSelf.radiusTouchRect, touchPoint) && weakSelf.selectorOverlay.editingRadius && !weakSelf.hidden){ 123 | if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(mapSelectorManagerWillBeginHandlingUserInteraction:)]) { 124 | [weakSelf.delegate mapSelectorManagerWillBeginHandlingUserInteraction:weakSelf]; 125 | } 126 | dispatch_async(dispatch_get_main_queue(), ^{ 127 | weakSelf.mapView.scrollEnabled = NO; 128 | weakSelf.mapView.userInteractionEnabled = NO; 129 | weakSelf.mapViewGestureEnabled = NO; 130 | }); 131 | } else { 132 | weakSelf.mapView.scrollEnabled = YES; 133 | weakSelf.mapView.userInteractionEnabled = YES; 134 | } 135 | weakSelf.prevMapPoint = mapPoint; 136 | weakSelf.prevRadius = weakSelf.circleRadius; 137 | }; 138 | 139 | selectorGestureRecognizer.touchesMovedCallback = ^(NSSet * touches, UIEvent * event) { 140 | if(!weakSelf.mapViewGestureEnabled && [event allTouches].count == 1){ 141 | UITouch *touch = [touches anyObject]; 142 | CGPoint touchPoint = [touch locationInView:weakSelf.mapView]; 143 | 144 | CLLocationCoordinate2D coord = [weakSelf.mapView convertPoint:touchPoint toCoordinateFromView:weakSelf.mapView]; 145 | MKMapPoint mapPoint = MKMapPointForCoordinate(coord); 146 | 147 | double meterDistance = (mapPoint.x - weakSelf.prevMapPoint.x)/MKMapPointsPerMeterAtLatitude(weakSelf.mapView.centerCoordinate.latitude) + weakSelf.prevRadius; 148 | weakSelf.circleRadius = MIN( MAX( meterDistance, weakSelf.circleRadiusMin ), weakSelf.circleRadiusMax ); 149 | } 150 | }; 151 | 152 | selectorGestureRecognizer.touchesEndedCallback = ^(NSSet * touches, UIEvent * event) { 153 | weakSelf.mapView.scrollEnabled = YES; 154 | weakSelf.mapView.userInteractionEnabled = YES; 155 | 156 | if (weakSelf.prevRadius != weakSelf.circleRadius) { 157 | [weakSelf recalculateRadiusTouchRect]; 158 | // if (((weakSelf.prevRadius / weakSelf.circleRadius) >= 1.25f) || ((weakSelf.prevRadius / weakSelf.circleRadius) <= .75f)) { 159 | [weakSelf updateMapRegionForMapSelector]; 160 | // } 161 | } 162 | if(!weakSelf.mapViewGestureEnabled) { 163 | if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(mapSelectorManagerDidHandleUserInteraction:)]) { 164 | dispatch_async(dispatch_get_main_queue(), ^{ 165 | [weakSelf.delegate mapSelectorManagerDidHandleUserInteraction:weakSelf]; 166 | }); 167 | } 168 | } 169 | weakSelf.mapViewGestureEnabled = YES; 170 | }; 171 | 172 | return selectorGestureRecognizer; 173 | } 174 | 175 | - (void)longPressGestureRecognizer:(UILongPressGestureRecognizer *)gestureRecognizer { 176 | if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] && 177 | ( self.editingType == DBMapSelectorEditingTypeFull || self.editingType == DBMapSelectorEditingTypeCoordinateOnly )) { 178 | switch (gestureRecognizer.state) { 179 | case UIGestureRecognizerStateBegan: { 180 | CGPoint touchPoint = [gestureRecognizer locationInView:self.mapView]; 181 | CLLocationCoordinate2D coord = [self.mapView convertPoint:touchPoint toCoordinateFromView:self.mapView]; 182 | self.circleCoordinate = coord; 183 | [self displaySelectorAnnotationIfNeeded]; 184 | break; 185 | } 186 | case UIGestureRecognizerStateEnded: 187 | if (NO == MKMapRectContainsRect(self.mapView.visibleMapRect, _selectorOverlay.boundingMapRect)) { 188 | [self updateMapRegionForMapSelector]; 189 | } 190 | break; 191 | default: 192 | break; 193 | } 194 | } 195 | } 196 | 197 | #pragma mark - Accessors 198 | 199 | - (void)setCircleRadius:(CLLocationDistance)circleRadius { 200 | if (_circleRadius!= MAX(MIN(circleRadius, _circleRadiusMax), _circleRadiusMin)) { 201 | _circleRadius = MAX(MIN(circleRadius, _circleRadiusMax), _circleRadiusMin); 202 | _selectorOverlay.radius = _circleRadius; 203 | if (_delegate && [_delegate respondsToSelector:@selector(mapSelectorManager:didChangeRadius:)]) { 204 | [_delegate mapSelectorManager:self 205 | didChangeRadius:_circleRadius]; 206 | } 207 | } 208 | } 209 | 210 | - (void)setCircleRadiusMax:(CLLocationDistance)circleRadiusMax { 211 | if (_circleRadiusMax != circleRadiusMax) { 212 | _circleRadiusMax = circleRadiusMax; 213 | _circleRadiusMin = MIN(_circleRadiusMin, _circleRadiusMax); 214 | self.circleRadius = _circleRadius; 215 | } 216 | } 217 | 218 | - (void)setCircleRadiusMin:(CLLocationDistance)circleRadiusMin { 219 | if (_circleRadiusMin != circleRadiusMin) { 220 | _circleRadiusMin = circleRadiusMin; 221 | _circleRadiusMax = MAX(_circleRadiusMax, _circleRadiusMin); 222 | self.circleRadius = _circleRadius; 223 | } 224 | } 225 | 226 | - (void)setCircleCoordinate:(CLLocationCoordinate2D)circleCoordinate { 227 | if ((_circleCoordinate.latitude != circleCoordinate.latitude) || (_circleCoordinate.longitude != circleCoordinate.longitude)) { 228 | _circleCoordinate = circleCoordinate; 229 | [self.mapView removeOverlay:_selectorOverlay]; 230 | _selectorOverlay.coordinate = _circleCoordinate; 231 | if (_hidden == NO) { 232 | [self.mapView addOverlay:_selectorOverlay]; 233 | } 234 | [self recalculateRadiusTouchRect]; 235 | if (_delegate && [_delegate respondsToSelector:@selector(mapSelectorManager:didChangeCoordinate:)]) { 236 | [_delegate mapSelectorManager:self 237 | didChangeCoordinate:_circleCoordinate]; 238 | } 239 | } 240 | } 241 | 242 | - (void)setFillColor:(UIColor *)fillColor { 243 | if (_fillColor != fillColor) { 244 | _fillColor = fillColor; 245 | _selectorOverlayRenderer.fillColor = fillColor; 246 | [_selectorOverlayRenderer invalidatePath]; 247 | } 248 | } 249 | 250 | - (void)setStrokeColor:(UIColor *)strokeColor { 251 | if (_strokeColor != strokeColor) { 252 | _strokeColor = strokeColor; 253 | _selectorOverlayRenderer.strokeColor = strokeColor; 254 | [_selectorOverlayRenderer invalidatePath]; 255 | } 256 | } 257 | 258 | - (void)setEditingType:(DBMapSelectorEditingType)editingType { 259 | if (_editingType != editingType) { 260 | _editingType = editingType; 261 | 262 | _selectorOverlay.editingCoordinate = (_editingType == DBMapSelectorEditingTypeCoordinateOnly || _editingType == DBMapSelectorEditingTypeFull); 263 | _selectorOverlay.editingRadius = (_editingType == DBMapSelectorEditingTypeRadiusOnly || _editingType == DBMapSelectorEditingTypeFull); 264 | [self displaySelectorAnnotationIfNeeded]; 265 | } 266 | } 267 | 268 | - (void)setHidden:(BOOL)hidden { 269 | if (_hidden != hidden) { 270 | _hidden = hidden; 271 | 272 | [self displaySelectorAnnotationIfNeeded]; 273 | if (_hidden) { 274 | [self.mapView removeOverlay:_selectorOverlay]; 275 | } else { 276 | [self.mapView addOverlay:_selectorOverlay]; 277 | } 278 | [self recalculateRadiusTouchRect]; 279 | } 280 | } 281 | 282 | - (void)setFillInside:(BOOL)fillInside { 283 | if (_fillInside != fillInside) { 284 | _fillInside = fillInside; 285 | _selectorOverlay.fillInside = fillInside; 286 | } 287 | } 288 | 289 | - (void)setShouldShowRadiusText:(BOOL)shouldShowRadiusText { 290 | _selectorOverlay.shouldShowRadiusText = shouldShowRadiusText; 291 | } 292 | 293 | - (void)setShouldLongPressGesture:(BOOL)shouldLongPressGesture { 294 | if (_shouldLongPressGesture != shouldLongPressGesture) { 295 | _shouldLongPressGesture = shouldLongPressGesture; 296 | if (_shouldLongPressGesture) { 297 | [self.mapView addGestureRecognizer:_longPressGestureRecognizer]; 298 | } else { 299 | [self.mapView removeGestureRecognizer:_longPressGestureRecognizer]; 300 | } 301 | } 302 | } 303 | 304 | #pragma mark - Additional 305 | 306 | - (void)recalculateRadiusTouchRect { 307 | MKMapRect selectorMapRect = _selectorOverlay.boundingMapRect; 308 | MKMapPoint selectorRadiusPoint = MKMapPointMake(MKMapRectGetMaxX(selectorMapRect), MKMapRectGetMidY(selectorMapRect)); 309 | MKCoordinateRegion coordinateRegion = MKCoordinateRegionMakeWithDistance(MKCoordinateForMapPoint(selectorRadiusPoint), _circleRadius *.3f, _circleRadius *.3f); 310 | BOOL needDisplay = MKMapRectContainsPoint(self.mapView.visibleMapRect, selectorRadiusPoint) && (_hidden == NO); 311 | _radiusTouchRect = needDisplay ? [self.mapView convertRegion:coordinateRegion toRectToView:self.mapView] : CGRectZero; 312 | #ifdef DEBUG 313 | _radiusTouchView.frame = _radiusTouchRect; 314 | _radiusTouchView.hidden = !needDisplay; 315 | #endif 316 | } 317 | 318 | - (void)updateMapRegionForMapSelector { 319 | MKCoordinateRegion selectorRegion = MKCoordinateRegionForMapRect(_selectorOverlay.boundingMapRect); 320 | MKCoordinateRegion region; 321 | region.center = selectorRegion.center; 322 | region.span = MKCoordinateSpanMake(selectorRegion.span.latitudeDelta * _mapRegionCoef, selectorRegion.span.longitudeDelta * _mapRegionCoef); 323 | [self.mapView setRegion:region animated:YES]; 324 | } 325 | 326 | - (void)displaySelectorAnnotationIfNeeded { 327 | for (id annotation in self.mapView.annotations) { 328 | if ([annotation isKindOfClass:[DBMapSelectorAnnotation class]]) { 329 | [self.mapView removeAnnotation:annotation]; 330 | } 331 | } 332 | 333 | if (_hidden == NO && ((_editingType == DBMapSelectorEditingTypeFull) || (_editingType == DBMapSelectorEditingTypeCoordinateOnly))) { 334 | DBMapSelectorAnnotation *selectorAnnotation = [[DBMapSelectorAnnotation alloc] init]; 335 | selectorAnnotation.coordinate = _circleCoordinate; 336 | [self.mapView addAnnotation:selectorAnnotation]; 337 | } 338 | } 339 | 340 | #pragma mark - MKMapView Delegate 341 | 342 | - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation { 343 | if ([annotation isKindOfClass:[DBMapSelectorAnnotation class]]) { 344 | static NSString *selectorIdentifier = @"DBMapSelectorAnnotationView"; 345 | MKPinAnnotationView *selectorAnnotationView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:selectorIdentifier]; 346 | if (selectorAnnotationView) { 347 | selectorAnnotationView.annotation = annotation; 348 | } else { 349 | selectorAnnotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:selectorIdentifier]; 350 | selectorAnnotationView.pinColor = MKPinAnnotationColorGreen; 351 | selectorAnnotationView.draggable = YES; 352 | } 353 | selectorAnnotationView.selected = YES; 354 | return selectorAnnotationView; 355 | } else { 356 | return nil; 357 | } 358 | } 359 | 360 | - (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState { 361 | if (newState == MKAnnotationViewDragStateStarting) { 362 | _mapViewGestureEnabled = YES; 363 | } 364 | if (newState == MKAnnotationViewDragStateEnding) { 365 | self.circleCoordinate = annotationView.annotation.coordinate; 366 | if (NO == MKMapRectContainsRect(mapView.visibleMapRect, _selectorOverlay.boundingMapRect)) { 367 | [self performSelector:@selector(updateMapRegionForMapSelector) 368 | withObject:nil 369 | afterDelay:.3f]; 370 | } 371 | } 372 | } 373 | 374 | - (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay { 375 | MKOverlayRenderer *overlayRenderer; 376 | if ([overlay isKindOfClass:[DBMapSelectorOverlay class]]) { 377 | _selectorOverlayRenderer = [[DBMapSelectorOverlayRenderer alloc] initWithSelectorOverlay:(DBMapSelectorOverlay *)overlay]; 378 | _selectorOverlayRenderer.fillColor = _fillColor; 379 | _selectorOverlayRenderer.strokeColor = _strokeColor; 380 | overlayRenderer = _selectorOverlayRenderer; 381 | } else if ([overlay isKindOfClass:[MKTileOverlay class]]) { 382 | overlayRenderer = [[MKTileOverlayRenderer alloc] initWithTileOverlay:overlay]; 383 | } 384 | return overlayRenderer; 385 | } 386 | 387 | - (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated { 388 | [self recalculateRadiusTouchRect]; 389 | } 390 | 391 | @end 392 | -------------------------------------------------------------------------------- /Source/MapSelectorAnnotation/DBMapSelectorAnnotation.h: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorAnnotation.h 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import 23 | #import 24 | 25 | @interface DBMapSelectorAnnotation : NSObject 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Source/MapSelectorAnnotation/DBMapSelectorAnnotation.m: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorAnnotation.m 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import "DBMapSelectorAnnotation.h" 23 | 24 | @implementation DBMapSelectorAnnotation 25 | 26 | @synthesize coordinate = _coordinate; 27 | 28 | - (void)setCoordinate:(CLLocationCoordinate2D)coordinate { 29 | _coordinate = coordinate; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Source/MapSelectorOverlay/DBMapSelectorOverlay.h: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorOverlay.h 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import 23 | #import 24 | 25 | @interface DBMapSelectorOverlay : NSObject 26 | 27 | @property (nonatomic, assign) CLLocationCoordinate2D coordinate; 28 | @property (nonatomic, assign) CLLocationDistance radius; 29 | @property (nonatomic, assign) BOOL editingCoordinate; 30 | @property (nonatomic, assign) BOOL editingRadius; 31 | @property (nonatomic, assign) BOOL fillInside; 32 | @property (nonatomic) BOOL shouldShowRadiusText; 33 | 34 | - (instancetype)initWithCenterCoordinate:(CLLocationCoordinate2D)coordinate radius:(CLLocationDistance)radius; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Source/MapSelectorOverlay/DBMapSelectorOverlay.m: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorOverlay.m 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import "DBMapSelectorOverlay.h" 23 | #import 24 | 25 | @implementation DBMapSelectorOverlay 26 | 27 | @synthesize boundingMapRect = _boundingMapRect; 28 | 29 | - (instancetype)initWithCenterCoordinate:(CLLocationCoordinate2D)coordinate radius:(CLLocationDistance)radius { 30 | self = [super init]; 31 | if (self) { 32 | _coordinate = coordinate; 33 | _radius = radius; 34 | _boundingMapRect = [self MKMapRectForCoordinate:_coordinate radius:_radius]; 35 | _editingCoordinate = YES; 36 | _editingRadius = YES; 37 | _fillInside = YES; 38 | _shouldShowRadiusText = YES; 39 | } 40 | return self; 41 | } 42 | 43 | #pragma mark - Accessor 44 | 45 | - (void)setCoordinate:(CLLocationCoordinate2D)coordinate { 46 | if ((_coordinate.latitude != coordinate.latitude) || (_coordinate.longitude != coordinate.longitude)) { 47 | _coordinate = coordinate; 48 | _boundingMapRect = [self MKMapRectForCoordinate:_coordinate radius:_radius]; 49 | } 50 | } 51 | 52 | - (void)setRadius:(CLLocationDistance)radius { 53 | if (_radius != radius) { 54 | _radius = radius; 55 | _boundingMapRect = [self MKMapRectForCoordinate:_coordinate radius:_radius]; 56 | } 57 | } 58 | 59 | #pragma mark - Additional 60 | 61 | - (MKMapRect)MKMapRectForCoordinate:(CLLocationCoordinate2D)coordinate radius:(CLLocationDistance)radius { 62 | MKCoordinateRegion r = MKCoordinateRegionMakeWithDistance(coordinate, radius *2.f, radius *2.f); 63 | MKMapPoint a = MKMapPointForCoordinate(CLLocationCoordinate2DMake(r.center.latitude + r.span.latitudeDelta *.5f, r.center.longitude - r.span.longitudeDelta *.5f)); 64 | MKMapPoint b = MKMapPointForCoordinate(CLLocationCoordinate2DMake(r.center.latitude - r.span.latitudeDelta *.5f, r.center.longitude + r.span.longitudeDelta *.5f)); 65 | return MKMapRectMake(MIN(a.x,b.x), MIN(a.y,b.y), ABS(a.x-b.x), ABS(a.y-b.y)); 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /Source/MapSelectorOverlay/DBMapSelectorOverlayRenderer.h: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorOverlayRenderer.h 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import 23 | 24 | @class DBMapSelectorOverlay; 25 | @interface DBMapSelectorOverlayRenderer : MKCircleRenderer 26 | 27 | - (instancetype)initWithSelectorOverlay:(DBMapSelectorOverlay *)selectorOverlay; 28 | + (NSString *)stringForRadius:(CLLocationDistance)a_radius; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Source/MapSelectorOverlay/DBMapSelectorOverlayRenderer.m: -------------------------------------------------------------------------------- 1 | // 2 | // DBMapSelectorOverlayRenderer.m 3 | // DBMapSelectorViewController 4 | // 5 | // Created by Denis Bogatyrev on 27.03.15. 6 | // 7 | // The MIT License (MIT) 8 | // Copyright (c) 2015 Denis Bogatyrev. 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 11 | // to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 12 | // and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 | // IN THE SOFTWARE. 20 | // 21 | 22 | #import "DBMapSelectorOverlayRenderer.h" 23 | #import "DBMapSelectorOverlay.h" 24 | 25 | static const CGFloat kDefaultAlphaComponent = .2f; 26 | static const CGFloat kCenterPointAlphaComponent = .75f; 27 | 28 | static const CGFloat kDefaultLineWidthCoef = .015f; 29 | static const CGFloat kFullLineWidthCoef = 1.f; 30 | static const CGFloat kDefaultPointRadiusCoef = .015f; 31 | static const CGFloat kEditCenterPointRadiusCoef = .1f; 32 | static const CGFloat kEditRadiusPointRadiusCoef = .05f; 33 | static const CGFloat kDefaultDashLineCoef = .01f; 34 | 35 | @interface DBMapSelectorOverlayRenderer () { 36 | DBMapSelectorOverlay *_selectorOverlay; 37 | } 38 | 39 | @end 40 | 41 | @implementation DBMapSelectorOverlayRenderer 42 | 43 | @synthesize fillColor = _fillColor; 44 | @synthesize strokeColor = _strokeColor; 45 | 46 | - (instancetype)initWithSelectorOverlay:(DBMapSelectorOverlay *)selectorOverlay { 47 | self = [super initWithOverlay:selectorOverlay]; 48 | if (self) { 49 | _selectorOverlay = selectorOverlay; 50 | _fillColor = [UIColor orangeColor]; 51 | _strokeColor = [UIColor darkGrayColor]; 52 | [self addOverlayObserver]; 53 | } 54 | return self; 55 | } 56 | 57 | - (void)dealloc { 58 | [self removeOverlayObserver]; 59 | } 60 | 61 | #pragma mark - Observering 62 | 63 | - (NSArray *)overlayObserverArray { 64 | return @[NSStringFromSelector(@selector(radius)), 65 | NSStringFromSelector(@selector(editingCoordinate)), 66 | NSStringFromSelector(@selector(editingRadius)), 67 | NSStringFromSelector(@selector(fillInside))]; 68 | } 69 | 70 | - (void)addOverlayObserver { 71 | for (NSString *keyPath in [self overlayObserverArray]) { 72 | [_selectorOverlay addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:nil]; 73 | } 74 | } 75 | 76 | - (void)removeOverlayObserver { 77 | for (NSString *keyPath in [self overlayObserverArray]) { 78 | [_selectorOverlay removeObserver:self forKeyPath:keyPath]; 79 | } 80 | } 81 | 82 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 83 | if ([object isKindOfClass:[_selectorOverlay class]]) { 84 | if ([[self overlayObserverArray] containsObject:keyPath]) { 85 | [self invalidatePath]; 86 | } 87 | } 88 | } 89 | 90 | #pragma mark - Drawing 91 | 92 | - (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context { 93 | MKMapPoint mpoint = MKMapPointForCoordinate([[self overlay] coordinate]); 94 | 95 | CLLocationDistance radius = _selectorOverlay.radius; 96 | CGFloat radiusAtLatitude = radius * MKMapPointsPerMeterAtLatitude([[self overlay] coordinate].latitude); 97 | 98 | MKMapRect circlebounds = MKMapRectMake(mpoint.x, mpoint.y, radiusAtLatitude *2.f, radiusAtLatitude *2.f); 99 | CGRect overlayRect = [self rectForMapRect:circlebounds]; 100 | 101 | [self drawMainCircleOverlayIfNeddedOnMapRect:mapRect fillInside:_selectorOverlay.fillInside radius:radiusAtLatitude overlayRect:overlayRect inContext:context]; 102 | [self drawCenterPointIfNeddedOnMapRect:mapRect allowEditing:_selectorOverlay.editingCoordinate radius:radiusAtLatitude overlayRect:overlayRect inContext:context]; 103 | [self drawRadiusPointIfNeddedOnMapRect:mapRect allowEditing:_selectorOverlay.editingRadius radius:radiusAtLatitude overlayRect:overlayRect inContext:context]; 104 | [self drawRadiusLineIfNeddedOnMapRect:mapRect showText:_selectorOverlay.shouldShowRadiusText centerMapPoint:mpoint radius:radius overlayRect:overlayRect zoomScale:zoomScale inContext:context]; 105 | } 106 | 107 | #pragma mark Helpers 108 | 109 | - (void)drawMainCircleOverlayIfNeddedOnMapRect:(MKMapRect)mapRect fillInside:(BOOL)fillInside radius:(CGFloat)radius overlayRect:(CGRect)overlayRect inContext:(CGContextRef)context { 110 | CGRect rect = [self rectForMapRect:mapRect]; 111 | if (fillInside && !CGRectIntersectsRect( rect, [self rectForMapRect:[self.overlay boundingMapRect]] )) { 112 | return; 113 | } 114 | 115 | CGContextSetStrokeColorWithColor(context, self.strokeColor.CGColor); 116 | CGContextSetLineWidth(context, overlayRect.size.width * kDefaultLineWidthCoef); 117 | CGContextSetShouldAntialias(context, YES); 118 | 119 | if (!fillInside) { 120 | CGRect rect = [self rectForMapRect:mapRect]; 121 | CGContextSaveGState(context); 122 | CGContextAddRect(context, rect); 123 | CGContextSetFillColorWithColor(context, [self.fillColor colorWithAlphaComponent:kDefaultAlphaComponent].CGColor); 124 | CGContextFillRect(context, rect); 125 | CGContextRestoreGState(context); 126 | 127 | CGContextSaveGState(context); 128 | CGContextSetFillColorWithColor(context, [UIColor whiteColor].CGColor); 129 | CGContextSetBlendMode(context, kCGBlendModeClear); 130 | CGContextFillEllipseInRect(context, [self rectForMapRect:[self.overlay boundingMapRect]]); 131 | CGContextRestoreGState(context); 132 | } 133 | 134 | CGContextSetFillColorWithColor(context, (fillInside ? [self.fillColor colorWithAlphaComponent:kDefaultAlphaComponent].CGColor : [UIColor clearColor].CGColor)); 135 | CGContextAddArc(context, overlayRect.origin.x, overlayRect.origin.y, radius, 0, 2 * M_PI, true); 136 | CGContextDrawPath(context, kCGPathFillStroke); 137 | } 138 | 139 | - (void)drawCenterPointIfNeddedOnMapRect:(MKMapRect)mapRect allowEditing:(BOOL)allowEdit radius:(CGFloat)radius overlayRect:(CGRect)overlayRect inContext:(CGContextRef)context { 140 | CGRect rect = [self rectForMapRect:mapRect]; 141 | CGFloat pointRadius = radius * (allowEdit ? kEditCenterPointRadiusCoef : kDefaultPointRadiusCoef); 142 | CGSize pointVisibleSize = CGSizeMake(pointRadius *3.f, pointRadius *3.f); // set 150% because drawing point with border line 143 | CGRect pointVisibleRect = CGRectMake(overlayRect.origin.x - pointVisibleSize.width *.5f, overlayRect.origin.y - pointVisibleSize.height *.5f, pointVisibleSize.width, pointVisibleSize.height) ; 144 | if (!CGRectIntersectsRect( rect, pointVisibleRect)) { 145 | return; 146 | } 147 | 148 | CGContextSetFillColorWithColor(context, [self.fillColor colorWithAlphaComponent:kCenterPointAlphaComponent].CGColor); 149 | CGContextAddArc(context, overlayRect.origin.x, overlayRect.origin.y, pointRadius, 0, 2 * M_PI, true); 150 | CGContextDrawPath(context, kCGPathFillStroke); 151 | } 152 | 153 | - (void)drawRadiusPointIfNeddedOnMapRect:(MKMapRect)mapRect allowEditing:(BOOL)allowEdit radius:(CGFloat)radius overlayRect:(CGRect)overlayRect inContext:(CGContextRef)context { 154 | CGRect rect = [self rectForMapRect:mapRect]; 155 | CGFloat pointRadius = radius * (allowEdit ? kEditRadiusPointRadiusCoef : kDefaultPointRadiusCoef); 156 | CGSize pointVisibleSize = CGSizeMake(pointRadius *3.f, pointRadius *3.f); // set 150% because drawing point with border line 157 | CGRect pointVisibleRect = CGRectMake(overlayRect.origin.x + radius - pointVisibleSize.width *.5f, overlayRect.origin.y - pointVisibleSize.height *.5f, pointVisibleSize.width, pointVisibleSize.height) ; 158 | if (!CGRectIntersectsRect( rect, pointVisibleRect)) { 159 | return; 160 | } 161 | 162 | CGContextSetFillColorWithColor(context, self.strokeColor.CGColor); 163 | CGContextAddArc(context, overlayRect.origin.x + radius, overlayRect.origin.y, pointRadius, 0, 2 * M_PI, true); 164 | CGContextDrawPath(context, kCGPathFillStroke); 165 | } 166 | 167 | - (void)drawRadiusLineIfNeddedOnMapRect:(MKMapRect)mapRect showText:(BOOL)showText centerMapPoint:(MKMapPoint)centerMapPoint radius:(CGFloat)radius overlayRect:(CGRect)overlayRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context { 168 | CGRect rect = [self rectForMapRect:mapRect]; 169 | CGSize lineVisibleSize = CGSizeMake(overlayRect.size.width *.5f, overlayRect.size.height *.15f); // set 15% of overlayRect.size for drawing line with text 170 | CGRect lineVisibleRect = CGRectMake(overlayRect.origin.x, overlayRect.origin.y - overlayRect.size.height *.1f, lineVisibleSize.width, lineVisibleSize.height) ; 171 | if (!CGRectIntersectsRect( rect, lineVisibleRect)) { 172 | return; 173 | } 174 | 175 | CGFloat kDashedLinesLength[] = {overlayRect.size.width * kDefaultDashLineCoef, overlayRect.size.width * kDefaultDashLineCoef}; 176 | CGContextSetLineWidth(context, overlayRect.size.width * kDefaultDashLineCoef); 177 | CGContextSetLineDash(context, .0f, kDashedLinesLength, kFullLineWidthCoef); 178 | 179 | CGContextMoveToPoint(context, overlayRect.origin.x + (_selectorOverlay.editingCoordinate ? overlayRect.size.width * kEditRadiusPointRadiusCoef : .0f), overlayRect.origin.y); 180 | CGContextAddLineToPoint(context, overlayRect.origin.x + overlayRect.size.width * .5f, overlayRect.origin.y); 181 | CGContextStrokePath(context); 182 | 183 | if (showText) { 184 | CGFloat fontSize = radius * zoomScale; 185 | NSString *radiusStr = [self.class stringForRadius:radius]; 186 | CGPoint point = CGPointMake([self pointForMapPoint:centerMapPoint].x + overlayRect.size.width * .18f, [self pointForMapPoint:centerMapPoint].y - overlayRect.size.width * .03f); 187 | CGContextSetFillColorWithColor(context, self.strokeColor.CGColor); 188 | #pragma clang diagnostic push 189 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 190 | CGContextSelectFont(context, "HelveticaNeue-Bold", fontSize, kCGEncodingMacRoman); 191 | #pragma clang diagnostic pop 192 | CGContextSetTextDrawingMode(context, kCGTextFill); 193 | CGAffineTransform xform = CGAffineTransformMakeScale(1.0 / zoomScale, -1.0 / zoomScale); 194 | CGContextSetTextMatrix(context, xform); 195 | #pragma clang diagnostic push 196 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 197 | CGContextShowTextAtPoint(context, point.x, point.y, [radiusStr cStringUsingEncoding:NSUTF8StringEncoding], radiusStr.length); 198 | #pragma clang diagnostic pop 199 | } 200 | } 201 | 202 | #pragma mark - Public 203 | 204 | + (NSString *)stringForRadius:(CLLocationDistance)radius { 205 | NSString *radiusStr = nil; 206 | if (radius >= 1000) { // 1000 meters 207 | NSString *diatanceOfKmStr = [NSString stringWithFormat:@"%.1f", radius * .001f]; 208 | radiusStr = [NSString stringWithFormat:NSLocalizedString(@"%@ km", @"RADIUS_IN_KILOMETRES km"), diatanceOfKmStr]; 209 | } else { 210 | NSString *diatanceOfMeterStr = [NSString stringWithFormat:@"%.0f", radius]; 211 | radiusStr = [NSString stringWithFormat:NSLocalizedString(@"%@ m", @"RADIUS IN METRES m"), diatanceOfMeterStr]; 212 | } 213 | return radiusStr; 214 | } 215 | 216 | @end 217 | --------------------------------------------------------------------------------