├── .gitignore ├── LICENSE ├── LocationPickerView-Demo ├── LocationPickerView-Demo.xcodeproj │ └── project.pbxproj └── LocationPickerView-Demo │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Default-568h@2x.png │ ├── Default.png │ ├── Default@2x.png │ ├── LocationPickerView-Demo-Info.plist │ ├── LocationPickerView-Demo-Prefix.pch │ ├── SecondViewController.h │ ├── SecondViewController.m │ ├── ViewController.h │ ├── ViewController.m │ ├── en.lproj │ ├── InfoPlist.strings │ └── MainStoryboard.storyboard │ └── main.m ├── LocationPickerView.podspec ├── LocationPickerView ├── LocationPickerView.h ├── LocationPickerView.m ├── UIImage+Icons.h └── UIImage+Icons.m ├── README.md └── github-images ├── 03.png ├── 04.png └── location-picker.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Christopher Constable - chris@futura.io 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 747B64DF173EFB4400DECD54 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 747B64DE173EFB4400DECD54 /* UIKit.framework */; }; 11 | 747B64E1173EFB4400DECD54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 747B64E0173EFB4400DECD54 /* Foundation.framework */; }; 12 | 747B64E3173EFB4400DECD54 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 747B64E2173EFB4400DECD54 /* CoreGraphics.framework */; }; 13 | 747B64E9173EFB4400DECD54 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 747B64E7173EFB4400DECD54 /* InfoPlist.strings */; }; 14 | 747B64EB173EFB4400DECD54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 747B64EA173EFB4400DECD54 /* main.m */; }; 15 | 747B64EF173EFB4400DECD54 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 747B64EE173EFB4400DECD54 /* AppDelegate.m */; }; 16 | 747B64F1173EFB4400DECD54 /* Default.png in Resources */ = {isa = PBXBuildFile; fileRef = 747B64F0173EFB4400DECD54 /* Default.png */; }; 17 | 747B64F3173EFB4400DECD54 /* Default@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 747B64F2173EFB4400DECD54 /* Default@2x.png */; }; 18 | 747B64F5173EFB4400DECD54 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 747B64F4173EFB4400DECD54 /* Default-568h@2x.png */; }; 19 | 747B64F8173EFB4400DECD54 /* MainStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 747B64F6173EFB4400DECD54 /* MainStoryboard.storyboard */; }; 20 | 747B64FB173EFB4400DECD54 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 747B64FA173EFB4400DECD54 /* ViewController.m */; }; 21 | 747B6506173EFB5900DECD54 /* LocationPickerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 747B6503173EFB5900DECD54 /* LocationPickerView.m */; }; 22 | 747B6507173EFB5900DECD54 /* UIImage+Icons.m in Sources */ = {isa = PBXBuildFile; fileRef = 747B6505173EFB5900DECD54 /* UIImage+Icons.m */; }; 23 | 747B6509173F35A900DECD54 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 747B6508173F35A900DECD54 /* MapKit.framework */; }; 24 | 747B650C173F388500DECD54 /* SecondViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 747B650B173F388500DECD54 /* SecondViewController.m */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 747B64DB173EFB4400DECD54 /* LocationPickerView-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "LocationPickerView-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 747B64DE173EFB4400DECD54 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 30 | 747B64E0173EFB4400DECD54 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 31 | 747B64E2173EFB4400DECD54 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 32 | 747B64E6173EFB4400DECD54 /* LocationPickerView-Demo-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "LocationPickerView-Demo-Info.plist"; sourceTree = ""; }; 33 | 747B64E8173EFB4400DECD54 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 34 | 747B64EA173EFB4400DECD54 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | 747B64EC173EFB4400DECD54 /* LocationPickerView-Demo-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "LocationPickerView-Demo-Prefix.pch"; sourceTree = ""; }; 36 | 747B64ED173EFB4400DECD54 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 37 | 747B64EE173EFB4400DECD54 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 38 | 747B64F0173EFB4400DECD54 /* Default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Default.png; sourceTree = ""; }; 39 | 747B64F2173EFB4400DECD54 /* Default@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default@2x.png"; sourceTree = ""; }; 40 | 747B64F4173EFB4400DECD54 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; 41 | 747B64F7173EFB4400DECD54 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = en; path = en.lproj/MainStoryboard.storyboard; sourceTree = ""; }; 42 | 747B64F9173EFB4400DECD54 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 43 | 747B64FA173EFB4400DECD54 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 44 | 747B6502173EFB5900DECD54 /* LocationPickerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LocationPickerView.h; sourceTree = ""; }; 45 | 747B6503173EFB5900DECD54 /* LocationPickerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocationPickerView.m; sourceTree = ""; }; 46 | 747B6504173EFB5900DECD54 /* UIImage+Icons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Icons.h"; sourceTree = ""; }; 47 | 747B6505173EFB5900DECD54 /* UIImage+Icons.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Icons.m"; sourceTree = ""; }; 48 | 747B6508173F35A900DECD54 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; }; 49 | 747B650A173F388500DECD54 /* SecondViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecondViewController.h; sourceTree = ""; }; 50 | 747B650B173F388500DECD54 /* SecondViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SecondViewController.m; sourceTree = ""; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | 747B64D8173EFB4400DECD54 /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | 747B6509173F35A900DECD54 /* MapKit.framework in Frameworks */, 59 | 747B64DF173EFB4400DECD54 /* UIKit.framework in Frameworks */, 60 | 747B64E1173EFB4400DECD54 /* Foundation.framework in Frameworks */, 61 | 747B64E3173EFB4400DECD54 /* CoreGraphics.framework in Frameworks */, 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 747B64D2173EFB4400DECD54 = { 69 | isa = PBXGroup; 70 | children = ( 71 | 747B6501173EFB5900DECD54 /* LocationPickerView */, 72 | 747B64E4173EFB4400DECD54 /* LocationPickerView-Demo */, 73 | 747B64DD173EFB4400DECD54 /* Frameworks */, 74 | 747B64DC173EFB4400DECD54 /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | 747B64DC173EFB4400DECD54 /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 747B64DB173EFB4400DECD54 /* LocationPickerView-Demo.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | 747B64DD173EFB4400DECD54 /* Frameworks */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 747B6508173F35A900DECD54 /* MapKit.framework */, 90 | 747B64DE173EFB4400DECD54 /* UIKit.framework */, 91 | 747B64E0173EFB4400DECD54 /* Foundation.framework */, 92 | 747B64E2173EFB4400DECD54 /* CoreGraphics.framework */, 93 | ); 94 | name = Frameworks; 95 | sourceTree = ""; 96 | }; 97 | 747B64E4173EFB4400DECD54 /* LocationPickerView-Demo */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 747B64ED173EFB4400DECD54 /* AppDelegate.h */, 101 | 747B64EE173EFB4400DECD54 /* AppDelegate.m */, 102 | 747B64F6173EFB4400DECD54 /* MainStoryboard.storyboard */, 103 | 747B64F9173EFB4400DECD54 /* ViewController.h */, 104 | 747B64FA173EFB4400DECD54 /* ViewController.m */, 105 | 747B650A173F388500DECD54 /* SecondViewController.h */, 106 | 747B650B173F388500DECD54 /* SecondViewController.m */, 107 | 747B64E5173EFB4400DECD54 /* Supporting Files */, 108 | ); 109 | path = "LocationPickerView-Demo"; 110 | sourceTree = ""; 111 | }; 112 | 747B64E5173EFB4400DECD54 /* Supporting Files */ = { 113 | isa = PBXGroup; 114 | children = ( 115 | 747B64E6173EFB4400DECD54 /* LocationPickerView-Demo-Info.plist */, 116 | 747B64E7173EFB4400DECD54 /* InfoPlist.strings */, 117 | 747B64EA173EFB4400DECD54 /* main.m */, 118 | 747B64EC173EFB4400DECD54 /* LocationPickerView-Demo-Prefix.pch */, 119 | 747B64F0173EFB4400DECD54 /* Default.png */, 120 | 747B64F2173EFB4400DECD54 /* Default@2x.png */, 121 | 747B64F4173EFB4400DECD54 /* Default-568h@2x.png */, 122 | ); 123 | name = "Supporting Files"; 124 | sourceTree = ""; 125 | }; 126 | 747B6501173EFB5900DECD54 /* LocationPickerView */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 747B6502173EFB5900DECD54 /* LocationPickerView.h */, 130 | 747B6503173EFB5900DECD54 /* LocationPickerView.m */, 131 | 747B6504173EFB5900DECD54 /* UIImage+Icons.h */, 132 | 747B6505173EFB5900DECD54 /* UIImage+Icons.m */, 133 | ); 134 | name = LocationPickerView; 135 | path = ../LocationPickerView; 136 | sourceTree = ""; 137 | }; 138 | /* End PBXGroup section */ 139 | 140 | /* Begin PBXNativeTarget section */ 141 | 747B64DA173EFB4400DECD54 /* LocationPickerView-Demo */ = { 142 | isa = PBXNativeTarget; 143 | buildConfigurationList = 747B64FE173EFB4400DECD54 /* Build configuration list for PBXNativeTarget "LocationPickerView-Demo" */; 144 | buildPhases = ( 145 | 747B64D7173EFB4400DECD54 /* Sources */, 146 | 747B64D8173EFB4400DECD54 /* Frameworks */, 147 | 747B64D9173EFB4400DECD54 /* Resources */, 148 | ); 149 | buildRules = ( 150 | ); 151 | dependencies = ( 152 | ); 153 | name = "LocationPickerView-Demo"; 154 | productName = "LocationPickerView-Demo"; 155 | productReference = 747B64DB173EFB4400DECD54 /* LocationPickerView-Demo.app */; 156 | productType = "com.apple.product-type.application"; 157 | }; 158 | /* End PBXNativeTarget section */ 159 | 160 | /* Begin PBXProject section */ 161 | 747B64D3173EFB4400DECD54 /* Project object */ = { 162 | isa = PBXProject; 163 | attributes = { 164 | LastUpgradeCheck = 0460; 165 | ORGANIZATIONNAME = "Christopher Constable"; 166 | }; 167 | buildConfigurationList = 747B64D6173EFB4400DECD54 /* Build configuration list for PBXProject "LocationPickerView-Demo" */; 168 | compatibilityVersion = "Xcode 3.2"; 169 | developmentRegion = English; 170 | hasScannedForEncodings = 0; 171 | knownRegions = ( 172 | en, 173 | ); 174 | mainGroup = 747B64D2173EFB4400DECD54; 175 | productRefGroup = 747B64DC173EFB4400DECD54 /* Products */; 176 | projectDirPath = ""; 177 | projectRoot = ""; 178 | targets = ( 179 | 747B64DA173EFB4400DECD54 /* LocationPickerView-Demo */, 180 | ); 181 | }; 182 | /* End PBXProject section */ 183 | 184 | /* Begin PBXResourcesBuildPhase section */ 185 | 747B64D9173EFB4400DECD54 /* Resources */ = { 186 | isa = PBXResourcesBuildPhase; 187 | buildActionMask = 2147483647; 188 | files = ( 189 | 747B64E9173EFB4400DECD54 /* InfoPlist.strings in Resources */, 190 | 747B64F1173EFB4400DECD54 /* Default.png in Resources */, 191 | 747B64F3173EFB4400DECD54 /* Default@2x.png in Resources */, 192 | 747B64F5173EFB4400DECD54 /* Default-568h@2x.png in Resources */, 193 | 747B64F8173EFB4400DECD54 /* MainStoryboard.storyboard in Resources */, 194 | ); 195 | runOnlyForDeploymentPostprocessing = 0; 196 | }; 197 | /* End PBXResourcesBuildPhase section */ 198 | 199 | /* Begin PBXSourcesBuildPhase section */ 200 | 747B64D7173EFB4400DECD54 /* Sources */ = { 201 | isa = PBXSourcesBuildPhase; 202 | buildActionMask = 2147483647; 203 | files = ( 204 | 747B64EB173EFB4400DECD54 /* main.m in Sources */, 205 | 747B64EF173EFB4400DECD54 /* AppDelegate.m in Sources */, 206 | 747B64FB173EFB4400DECD54 /* ViewController.m in Sources */, 207 | 747B6506173EFB5900DECD54 /* LocationPickerView.m in Sources */, 208 | 747B6507173EFB5900DECD54 /* UIImage+Icons.m in Sources */, 209 | 747B650C173F388500DECD54 /* SecondViewController.m in Sources */, 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | }; 213 | /* End PBXSourcesBuildPhase section */ 214 | 215 | /* Begin PBXVariantGroup section */ 216 | 747B64E7173EFB4400DECD54 /* InfoPlist.strings */ = { 217 | isa = PBXVariantGroup; 218 | children = ( 219 | 747B64E8173EFB4400DECD54 /* en */, 220 | ); 221 | name = InfoPlist.strings; 222 | sourceTree = ""; 223 | }; 224 | 747B64F6173EFB4400DECD54 /* MainStoryboard.storyboard */ = { 225 | isa = PBXVariantGroup; 226 | children = ( 227 | 747B64F7173EFB4400DECD54 /* en */, 228 | ); 229 | name = MainStoryboard.storyboard; 230 | sourceTree = ""; 231 | }; 232 | /* End PBXVariantGroup section */ 233 | 234 | /* Begin XCBuildConfiguration section */ 235 | 747B64FC173EFB4400DECD54 /* Debug */ = { 236 | isa = XCBuildConfiguration; 237 | buildSettings = { 238 | ALWAYS_SEARCH_USER_PATHS = NO; 239 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 240 | CLANG_CXX_LIBRARY = "libc++"; 241 | CLANG_ENABLE_OBJC_ARC = YES; 242 | CLANG_WARN_CONSTANT_CONVERSION = YES; 243 | CLANG_WARN_EMPTY_BODY = YES; 244 | CLANG_WARN_ENUM_CONVERSION = YES; 245 | CLANG_WARN_INT_CONVERSION = YES; 246 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 247 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 248 | COPY_PHASE_STRIP = NO; 249 | GCC_C_LANGUAGE_STANDARD = gnu99; 250 | GCC_DYNAMIC_NO_PIC = NO; 251 | GCC_OPTIMIZATION_LEVEL = 0; 252 | GCC_PREPROCESSOR_DEFINITIONS = ( 253 | "DEBUG=1", 254 | "$(inherited)", 255 | ); 256 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 257 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 258 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 259 | GCC_WARN_UNUSED_VARIABLE = YES; 260 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 261 | ONLY_ACTIVE_ARCH = YES; 262 | SDKROOT = iphoneos; 263 | }; 264 | name = Debug; 265 | }; 266 | 747B64FD173EFB4400DECD54 /* Release */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | ALWAYS_SEARCH_USER_PATHS = NO; 270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 271 | CLANG_CXX_LIBRARY = "libc++"; 272 | CLANG_ENABLE_OBJC_ARC = YES; 273 | CLANG_WARN_CONSTANT_CONVERSION = YES; 274 | CLANG_WARN_EMPTY_BODY = YES; 275 | CLANG_WARN_ENUM_CONVERSION = YES; 276 | CLANG_WARN_INT_CONVERSION = YES; 277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 278 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 279 | COPY_PHASE_STRIP = YES; 280 | GCC_C_LANGUAGE_STANDARD = gnu99; 281 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 283 | GCC_WARN_UNUSED_VARIABLE = YES; 284 | IPHONEOS_DEPLOYMENT_TARGET = 6.1; 285 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 286 | SDKROOT = iphoneos; 287 | VALIDATE_PRODUCT = YES; 288 | }; 289 | name = Release; 290 | }; 291 | 747B64FF173EFB4400DECD54 /* Debug */ = { 292 | isa = XCBuildConfiguration; 293 | buildSettings = { 294 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 295 | GCC_PREFIX_HEADER = "LocationPickerView-Demo/LocationPickerView-Demo-Prefix.pch"; 296 | INFOPLIST_FILE = "LocationPickerView-Demo/LocationPickerView-Demo-Info.plist"; 297 | PRODUCT_NAME = "$(TARGET_NAME)"; 298 | WRAPPER_EXTENSION = app; 299 | }; 300 | name = Debug; 301 | }; 302 | 747B6500173EFB4400DECD54 /* Release */ = { 303 | isa = XCBuildConfiguration; 304 | buildSettings = { 305 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 306 | GCC_PREFIX_HEADER = "LocationPickerView-Demo/LocationPickerView-Demo-Prefix.pch"; 307 | INFOPLIST_FILE = "LocationPickerView-Demo/LocationPickerView-Demo-Info.plist"; 308 | PRODUCT_NAME = "$(TARGET_NAME)"; 309 | WRAPPER_EXTENSION = app; 310 | }; 311 | name = Release; 312 | }; 313 | /* End XCBuildConfiguration section */ 314 | 315 | /* Begin XCConfigurationList section */ 316 | 747B64D6173EFB4400DECD54 /* Build configuration list for PBXProject "LocationPickerView-Demo" */ = { 317 | isa = XCConfigurationList; 318 | buildConfigurations = ( 319 | 747B64FC173EFB4400DECD54 /* Debug */, 320 | 747B64FD173EFB4400DECD54 /* Release */, 321 | ); 322 | defaultConfigurationIsVisible = 0; 323 | defaultConfigurationName = Release; 324 | }; 325 | 747B64FE173EFB4400DECD54 /* Build configuration list for PBXNativeTarget "LocationPickerView-Demo" */ = { 326 | isa = XCConfigurationList; 327 | buildConfigurations = ( 328 | 747B64FF173EFB4400DECD54 /* Debug */, 329 | 747B6500173EFB4400DECD54 /* Release */, 330 | ); 331 | defaultConfigurationIsVisible = 0; 332 | }; 333 | /* End XCConfigurationList section */ 334 | }; 335 | rootObject = 747B64D3173EFB4400DECD54 /* Project object */; 336 | } 337 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LocationPickerView-Demo 4 | // 5 | // Created by Christopher Constable on 5/11/13. 6 | // Copyright (c) 2013 Christopher Constable. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // LocationPickerView-Demo 4 | // 5 | // Created by Christopher Constable on 5/11/13. 6 | // Copyright (c) 2013 Christopher Constable. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @implementation AppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // 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. 22 | // 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. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // 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. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // 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. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 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 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cconstable/LocationPickerView/4bce9ac0b5ad5780baa5bd6bca8d32bd58c699b9/LocationPickerView-Demo/LocationPickerView-Demo/Default-568h@2x.png -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cconstable/LocationPickerView/4bce9ac0b5ad5780baa5bd6bca8d32bd58c699b9/LocationPickerView-Demo/LocationPickerView-Demo/Default.png -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cconstable/LocationPickerView/4bce9ac0b5ad5780baa5bd6bca8d32bd58c699b9/LocationPickerView-Demo/LocationPickerView-Demo/Default@2x.png -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/LocationPickerView-Demo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | Christopher-Constable.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationPortraitUpsideDown 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/LocationPickerView-Demo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'LocationPickerView-Demo' target in the 'LocationPickerView-Demo' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_5_0 8 | #warning "This project uses features only available in iOS SDK 5.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #endif 15 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // LocationPickerView-Demo 4 | // 5 | // Created by Christopher Constable on 5/11/13. 6 | // Copyright (c) 2013 Christopher Constable. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SecondViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // LocationPickerView-Demo 4 | // 5 | // Created by Christopher Constable on 5/11/13. 6 | // Copyright (c) 2013 Christopher Constable. All rights reserved. 7 | // 8 | 9 | #import "SecondViewController.h" 10 | 11 | @interface SecondViewController () 12 | 13 | @end 14 | 15 | @implementation SecondViewController 16 | 17 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 18 | { 19 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 20 | if (self) { 21 | // Custom initialization 22 | } 23 | return self; 24 | } 25 | 26 | - (void)viewDidLoad 27 | { 28 | [super viewDidLoad]; 29 | // Do any additional setup after loading the view. 30 | } 31 | 32 | - (void)didReceiveMemoryWarning 33 | { 34 | [super didReceiveMemoryWarning]; 35 | // Dispose of any resources that can be recreated. 36 | } 37 | 38 | #pragma mark - UITableView 39 | 40 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 41 | { 42 | return 60; 43 | } 44 | 45 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 46 | { 47 | return 20; 48 | } 49 | 50 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 51 | { 52 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"reusable"]; 53 | if (!cell) { 54 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"reusable"]; 55 | } 56 | 57 | cell.textLabel.text = @"This location picker..."; 58 | cell.detailTextLabel.text = @"was created using the storyboard (no code)."; 59 | 60 | return cell; 61 | } 62 | 63 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 64 | { 65 | [self.view endEditing:YES]; 66 | [tableView deselectRowAtIndexPath:indexPath animated:NO]; 67 | } 68 | 69 | - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 70 | { 71 | cell.contentView.backgroundColor = [UIColor whiteColor]; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // LocationPickerView-Demo 4 | // 5 | // Created by Christopher Constable on 5/11/13. 6 | // Copyright (c) 2013 Christopher Constable. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "LocationPickerView.h" 11 | 12 | @interface ViewController : UIViewController 13 | 14 | @property (nonatomic, strong) LocationPickerView *locationPickerView; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // LocationPickerView-Demo 4 | // 5 | // Created by Christopher Constable on 5/11/13. 6 | // Copyright (c) 2013 Christopher Constable. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ViewController.h" 11 | 12 | @interface ViewController () 13 | 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad 19 | { 20 | [super viewDidLoad]; 21 | 22 | // The LocationPickerView can be created programmatically (see below) or 23 | // using Storyboards/XIBs (see Storyboard file). 24 | self.locationPickerView = [[LocationPickerView alloc] initWithFrame:self.view.bounds]; 25 | self.locationPickerView.tableViewDataSource = self; 26 | self.locationPickerView.tableViewDelegate = self; 27 | 28 | // Optional parameters 29 | self.locationPickerView.delegate = self; 30 | self.locationPickerView.shouldAutoCenterOnUserLocation = YES; 31 | self.locationPickerView.shouldCreateHideMapButton = YES; 32 | self.locationPickerView.pullToExpandMapEnabled = YES; 33 | self.locationPickerView.defaultMapHeight = 220.0; // larger than normal 34 | self.locationPickerView.parallaxScrollFactor = 0.3; // little slower than normal. 35 | 36 | // Optional setup 37 | self.locationPickerView.mapViewDidLoadBlock = ^(LocationPickerView *locationPicker) { 38 | locationPicker.mapView.mapType = MKMapTypeStandard; 39 | locationPicker.mapView.userTrackingMode = MKUserTrackingModeFollow; 40 | }; 41 | self.locationPickerView.tableViewDidLoadBlock = ^(LocationPickerView *locationPicker) { 42 | locationPicker.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 43 | }; 44 | 45 | // set custom close button 46 | /* 47 | UIButton *customCloseButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 48 | [customCloseButton setTitle:@"close" forState:UIControlStateNormal]; 49 | [customCloseButton setBackgroundColor:[UIColor blueColor]]; 50 | [customCloseButton setFrame:CGRectMake(0, 0, 80, 80)]; 51 | [self.locationPickerView setCustomCloseButton:customCloseButton atPoint:CGPointMake(100, 400)]; 52 | */ 53 | 54 | [self.view addSubview:self.locationPickerView]; 55 | } 56 | 57 | - (void)didReceiveMemoryWarning 58 | { 59 | [super didReceiveMemoryWarning]; 60 | // Dispose of any resources that can be recreated. 61 | } 62 | 63 | #pragma mark - UITableView 64 | 65 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 66 | { 67 | return 20; 68 | } 69 | 70 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 71 | { 72 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"reusable"]; 73 | if (!cell) { 74 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"reusable"]; 75 | } 76 | 77 | cell.textLabel.text = [NSString stringWithFormat:@"Row %d", indexPath.row]; 78 | 79 | return cell; 80 | } 81 | 82 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 83 | { 84 | [tableView deselectRowAtIndexPath:indexPath animated:NO]; 85 | [self performSegueWithIdentifier:@"Second" sender:self]; 86 | } 87 | 88 | - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath 89 | { 90 | cell.contentView.backgroundColor = [UIColor whiteColor]; 91 | } 92 | 93 | #pragma mark - LocationPickerViewDelegate 94 | 95 | /** Called when the mapView is about to be expanded (made fullscreen). 96 | Use this to perform custom animations or set attributes of the map/table. */ 97 | - (void)locationPicker:(LocationPickerView *)locationPicker 98 | mapViewWillExpand:(MKMapView *)mapView 99 | { 100 | self.navigationItem.title = @"Map Expanding"; 101 | } 102 | 103 | /** Called when the mapView was expanded (made fullscreen). Use this to 104 | perform custom animations or set attributes of the map/table. */ 105 | - (void)locationPicker:(LocationPickerView *)locationPicker 106 | mapViewDidExpand:(MKMapView *)mapView 107 | { 108 | self.navigationItem.title = @"Map Expanded"; 109 | } 110 | 111 | /** Called when the mapView is about to be hidden (made tiny). Use this to 112 | perform custom animations or set attributes of the map/table. */ 113 | - (void)locationPicker:(LocationPickerView *)locationPicker 114 | mapViewWillBeHidden:(MKMapView *)mapView 115 | { 116 | self.navigationItem.title = @"Map Shrinking"; 117 | } 118 | 119 | /** Called when the mapView was hidden (made tiny). Use this to 120 | perform custom animations or set attributes of the map/table. */ 121 | - (void)locationPicker:(LocationPickerView *)locationPicker 122 | mapViewWasHidden:(MKMapView *)mapView 123 | { 124 | self.navigationItem.title = @"Map Normal"; 125 | } 126 | 127 | - (void)locationPicker:(LocationPickerView *)locationPicker mapViewDidLoad:(MKMapView *)mapView 128 | { 129 | mapView.mapType = MKMapTypeStandard; 130 | } 131 | 132 | - (void)locationPicker:(LocationPickerView *)locationPicker tableViewDidLoad:(UITableView *)tableView 133 | { 134 | tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 135 | } 136 | 137 | 138 | @end 139 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/en.lproj/MainStoryboard.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 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /LocationPickerView-Demo/LocationPickerView-Demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LocationPickerView-Demo 4 | // 5 | // Created by Christopher Constable on 5/11/13. 6 | // Copyright (c) 2013 Christopher Constable. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LocationPickerView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "LocationPickerView" 3 | s.version = "1.2.0" 4 | s.summary = "MKMapView + UITableView + Parallax scrolling. Provides a framework for building an interactive location picker on iOS." 5 | s.homepage = "https://github.com/mstrchrstphr/LocationPickerView" 6 | s.screenshots = "https://raw.github.com/mstrchrstphr/LocationPickerView/master/github-images/location-picker.gif" 7 | s.license = { :type => 'MIT', :file => 'LICENSE' } 8 | s.author = { "Christopher Constable" => "chris@futura.io" } 9 | s.source = { :git => "https://github.com/mstrchrstphr/LocationPickerView.git", :tag => "1.2.0" } 10 | s.source_files = 'LocationPickerView/**/*.{h,m}' 11 | s.framework = 'UIKit', 'MapKit' 12 | s.requires_arc = true 13 | s.platform = :ios, '5.0' 14 | end 15 | -------------------------------------------------------------------------------- /LocationPickerView/LocationPickerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LocationPickerView.h 3 | // 4 | // Created by Christopher Constable on 5/10/13. 5 | // Copyright (c) 2013 Futura IO. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | 11 | @class MKMapView; 12 | @class LocationPickerView; 13 | 14 | @protocol MKMapViewDelegate; 15 | @protocol LocationPickerViewDelegate; 16 | 17 | typedef void (^LocationPickerViewBlock)(LocationPickerView *locationPicker); 18 | 19 | 20 | @interface LocationPickerView : UIView 21 | 22 | /** How much of the screen the map takes up initially and the height 23 | it returns to after scrolling is done. By default this is set to 24 | "180.0f". */ 25 | @property (nonatomic) CGFloat defaultMapHeight; 26 | 27 | /** How fast the map scrolls with the table view. If this is set to 28 | "1.0" it scrolls at the same speed. A value less than "1.0" produces 29 | a slower scrolling map while a value greater than "1.0" makes the map 30 | scroll faster. The default value is "0.5". */ 31 | @property (nonatomic) CGFloat parallaxScrollFactor; 32 | 33 | /** Determines whether or not the user can pull to a certain point 34 | on the table view to expand the map. This is disabled by default 35 | because it may interfere with pull-to-refresh or other controls. */ 36 | @property (nonatomic) BOOL pullToExpandMapEnabled; 37 | 38 | /** The amount you must "pull down" on the scroll view to make the 39 | map view pop-out to full screen. By default this is set to "140.0f". */ 40 | @property (nonatomic) CGFloat amountToScrollToFullScreenMap; 41 | 42 | /** If set to YES, this will automatically create an "X" button to shrink 43 | the map back down when it is shown. The button hides when the map returns 44 | to it's default size. This property defaults to NO. */ 45 | @property (nonatomic) BOOL shouldCreateHideMapButton; 46 | 47 | /** If the map is tracking the user location and this variable is set to 'YES', 48 | the map will automatically center on the user's location when shrinking / expanding. 49 | This defaults to NO. */ 50 | @property (nonatomic) BOOL shouldAutoCenterOnUserLocation; 51 | 52 | /** Is the map covering the full screen? */ 53 | @property (nonatomic, readonly) BOOL isMapFullScreen; 54 | 55 | /** The delegate gets notified when the map expands, shrinks, etc. */ 56 | @property (nonatomic, weak) IBOutlet id delegate; 57 | 58 | /** The map view, duh. */ 59 | @property (nonatomic, strong) MKMapView *mapView; 60 | 61 | /** Table view that sits below the map. */ 62 | @property (nonatomic, strong) UITableView *tableView; 63 | 64 | /** The view to the tableview background view. */ 65 | @property (nonatomic, strong) UIView *backgroundView; 66 | 67 | /** The color of the backgroundView */ 68 | @property (nonatomic, strong) UIColor *backgroundViewColor; 69 | 70 | /** This UITableViewDataSource is forwarded to the LocationPickers's 71 | UITableView when it is created. */ 72 | @property (nonatomic, weak) IBOutlet id tableViewDataSource; 73 | 74 | /** This UITableViewDelegate is forwarded to the LocationPickers's 75 | UITableView when it is created. */ 76 | @property (nonatomic, weak) IBOutlet id tableViewDelegate; 77 | 78 | /** This MKMapViewDelegate is forwarded to the LocationPickers's 79 | MKMapView when it is created. */ 80 | @property (nonatomic, weak) IBOutlet id mapViewDelegate; 81 | 82 | /** Called after the tableView has been loaded. Allows for additional setup. */ 83 | @property (nonatomic, copy) LocationPickerViewBlock tableViewDidLoadBlock; 84 | 85 | /** Called after the mapView has been loaded. Allows for additional setup. */ 86 | @property (nonatomic, copy) LocationPickerViewBlock mapViewDidLoadBlock; 87 | 88 | @property (nonatomic, copy) LocationPickerViewBlock mapViewWillExpand; 89 | @property (nonatomic, copy) LocationPickerViewBlock mapViewDidExpand; 90 | @property (nonatomic, copy) LocationPickerViewBlock mapViewWillBeHidden; 91 | @property (nonatomic, copy) LocationPickerViewBlock mapViewWasHidden; 92 | 93 | /* custom action for close map view button, overrides default action */ 94 | @property (nonatomic, copy) LocationPickerViewBlock mapCloseButtonTapped; 95 | 96 | /** Makes the map view full screen. */ 97 | - (void)expandMapView:(id)sender animated:(BOOL)animated; 98 | - (IBAction)expandMapView:(id)sender; 99 | 100 | /** Shrinks the map view back down to it's default height. */ 101 | - (void)hideMapView:(id)sender animated:(BOOL)animated; 102 | - (IBAction)hideMapView:(id)sender; 103 | 104 | /** Expands or shrinks the map view. */ 105 | - (IBAction)toggleMapView:(id)sender; 106 | 107 | /** Set custom close button map */ 108 | - (void)setCustomCloseButton:(UIButton *)closeButton; 109 | 110 | /** Set custom close button map at x/y point */ 111 | - (void)setCustomCloseButton:(UIButton *)closeButton atPoint:(CGPoint)buttonPoint; 112 | 113 | @end 114 | 115 | 116 | @protocol LocationPickerViewDelegate 117 | 118 | @optional 119 | 120 | /** Called when the mapView is loaded or reloaded. Alternatively, the block 121 | properties of LocationPickerView can be used. */ 122 | - (void)locationPicker:(LocationPickerView *)locationPicker 123 | mapViewDidLoad:(MKMapView *)mapView; 124 | 125 | /** Called when the tableView is loaded or reloaded. Alternatively, the block 126 | properties of LocationPickerView can be used. */ 127 | - (void)locationPicker:(LocationPickerView *)locationPicker 128 | tableViewDidLoad:(UITableView *)tableView; 129 | 130 | /** Called when the mapView is about to be expanded (made fullscreen). 131 | Use this to perform custom animations or set attributes of the map/table. */ 132 | - (void)locationPicker:(LocationPickerView *)locationPicker 133 | mapViewWillExpand:(MKMapView *)mapView; 134 | 135 | /** Called when the mapView was expanded (made fullscreen). Use this to 136 | perform custom animations or set attributes of the map/table. */ 137 | - (void)locationPicker:(LocationPickerView *)locationPicker 138 | mapViewDidExpand:(MKMapView *)mapView; 139 | 140 | /** Called when the mapView is about to be hidden (made tiny). Use this to 141 | perform custom animations or set attributes of the map/table. */ 142 | - (void)locationPicker:(LocationPickerView *)locationPicker 143 | mapViewWillBeHidden:(MKMapView *)mapView; 144 | 145 | /** Called when the mapView was hidden (made tiny). Use this to 146 | perform custom animations or set attributes of the map/table. */ 147 | - (void)locationPicker:(LocationPickerView *)locationPicker 148 | mapViewWasHidden:(MKMapView *)mapView; 149 | 150 | @end 151 | -------------------------------------------------------------------------------- /LocationPickerView/LocationPickerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LocationPickerView.m 3 | // 4 | // Created by Christopher Constable on 5/10/13. 5 | // Copyright (c) 2013 Futura IO. All rights reserved. 6 | // 7 | 8 | #import 9 | #import "LocationPickerView.h" 10 | #import "UIImage+Icons.h" 11 | 12 | @interface LocationPickerView () 13 | 14 | @property (nonatomic) BOOL isMapAnimating; 15 | @property (nonatomic) CGRect defaultMapViewFrame; 16 | @property (nonatomic, strong) UITapGestureRecognizer *mapTapGesture; 17 | 18 | /** This is only created if the user does not override the 19 | mapViewDidExpand: method. Allows the user to shrink the map. */ 20 | @property (nonatomic, strong) UIButton *closeMapButton; 21 | @property (nonatomic, readwrite) CGPoint closeButtonPoint; 22 | - (void)didTapCloseMapViewButton:(id)sender; 23 | @end 24 | 25 | @implementation LocationPickerView 26 | 27 | - (id)init 28 | { 29 | self = [super init]; 30 | if (self) { 31 | [self initialize]; 32 | } 33 | return self; 34 | } 35 | 36 | - (id)initWithFrame:(CGRect)frame 37 | { 38 | self = [super initWithFrame:frame]; 39 | if (self) { 40 | [self initialize]; 41 | } 42 | return self; 43 | } 44 | 45 | - (id)initWithCoder:(NSCoder *)aDecoder 46 | { 47 | self = [super initWithCoder:aDecoder]; 48 | if (self) { 49 | [self initialize]; 50 | } 51 | return self; 52 | } 53 | 54 | - (void)initialize 55 | { 56 | _defaultMapHeight = 130.0f; 57 | _parallaxScrollFactor = 0.6f; 58 | _amountToScrollToFullScreenMap = 110.0f; 59 | _shouldAutoCenterOnUserLocation = NO; 60 | self.autoresizesSubviews = YES; 61 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | 62 | UIViewAutoresizingFlexibleHeight; 63 | 64 | self.closeButtonPoint = CGPointMake(14.0, 14.0); 65 | self.backgroundViewColor = [UIColor clearColor]; 66 | } 67 | 68 | - (void)dealloc 69 | { 70 | void *context = (__bridge void *)self; 71 | [self.tableView removeObserver:self forKeyPath:@"contentOffset" context:context]; 72 | [self.mapView removeObserver:self forKeyPath:@"userTrackingMode" context:context]; 73 | [self.mapView.userLocation removeObserver:self forKeyPath:@"location" context:context]; 74 | 75 | } 76 | 77 | 78 | - (void)layoutSubviews 79 | { 80 | [super layoutSubviews]; 81 | 82 | if (!self.tableView) { 83 | _tableView = [[UITableView alloc] initWithFrame:self.bounds]; 84 | self.tableView.backgroundColor = [UIColor clearColor]; 85 | self.tableView.delegate = self.tableViewDelegate; 86 | self.tableView.dataSource = self.tableViewDataSource; 87 | self.tableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | 88 | UIViewAutoresizingFlexibleHeight; 89 | 90 | if ([self.delegate respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) { 91 | self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(64.0, 0.0, 0.0, 0.0); 92 | } 93 | 94 | void *context = (__bridge void *)self; 95 | [self.tableView addObserver:self 96 | forKeyPath:@"contentOffset" 97 | options:NSKeyValueObservingOptionNew 98 | context:context]; 99 | 100 | [self addSubview:self.tableView]; 101 | 102 | if ([self.delegate respondsToSelector:@selector(locationPicker:tableViewDidLoad:)]) { 103 | [self.delegate locationPicker:self tableViewDidLoad:self.tableView]; 104 | } 105 | 106 | if (self.tableViewDidLoadBlock) { 107 | self.tableViewDidLoadBlock(self); 108 | } 109 | } 110 | 111 | if (!self.tableView.tableHeaderView) { 112 | CGRect tableHeaderViewFrame = CGRectMake(0.0, 0.0, self.tableView.frame.size.width, self.defaultMapHeight); 113 | UIView *tableHeaderView = [[UIView alloc] initWithFrame:tableHeaderViewFrame]; 114 | tableHeaderView.backgroundColor = [UIColor clearColor]; 115 | self.tableView.tableHeaderView = tableHeaderView; 116 | } 117 | 118 | if (!self.mapView) { 119 | self.defaultMapViewFrame = CGRectMake(0.0, 120 | -self.defaultMapHeight * self.parallaxScrollFactor * 2, 121 | self.tableView.frame.size.width, 122 | self.defaultMapHeight + (self.defaultMapHeight * self.parallaxScrollFactor * 4)); 123 | _mapView = [[MKMapView alloc] initWithFrame:self.defaultMapViewFrame]; 124 | self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 125 | self.mapView.scrollEnabled = NO; 126 | self.mapView.zoomEnabled = NO; 127 | self.mapView.delegate = self.mapViewDelegate; 128 | [self insertSubview:self.mapView belowSubview:self.tableView]; 129 | 130 | void *context = (__bridge void *)self; 131 | [self.mapView.userLocation addObserver:self 132 | forKeyPath:@"location" 133 | options:NSKeyValueObservingOptionNew 134 | context:context]; 135 | 136 | [self.mapView addObserver:self 137 | forKeyPath:@"userTrackingMode" 138 | options:NSKeyValueObservingOptionNew 139 | context:context]; 140 | 141 | if ([self.delegate respondsToSelector:@selector(locationPicker:mapViewDidLoad:)]) { 142 | [self.delegate locationPicker:self mapViewDidLoad:self.mapView]; 143 | } 144 | 145 | if (self.mapViewDidLoadBlock) { 146 | self.mapViewDidLoadBlock(self); 147 | } 148 | } 149 | 150 | // Add tap gesture to table 151 | if (!self.mapTapGesture) { 152 | self.mapTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self 153 | action:@selector(mapWasTapped:)]; 154 | self.mapTapGesture.cancelsTouchesInView = YES; 155 | self.mapTapGesture.delaysTouchesBegan = NO; 156 | [self.tableView.tableHeaderView addGestureRecognizer:self.mapTapGesture]; 157 | } 158 | 159 | // Add the background tableView 160 | if (!self.backgroundView) { 161 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0.0, self.defaultMapHeight, 162 | self.tableView.frame.size.width, 163 | self.tableView.frame.size.height - self.defaultMapHeight)]; 164 | view.backgroundColor = self.backgroundViewColor; 165 | self.backgroundView = view; 166 | self.backgroundView.userInteractionEnabled=NO; 167 | [self.tableView insertSubview:self.backgroundView atIndex:0]; 168 | } 169 | } 170 | 171 | - (void)setTableViewDataSource:(id)tableViewDataSource 172 | { 173 | _tableViewDataSource = tableViewDataSource; 174 | self.tableView.dataSource = _tableViewDataSource; 175 | 176 | if (_tableViewDelegate) { 177 | [self.tableView reloadData]; 178 | } 179 | } 180 | 181 | - (void)setTableViewDelegate:(id)tableViewDelegate 182 | { 183 | _tableViewDelegate = tableViewDelegate; 184 | self.tableView.delegate = _tableViewDelegate; 185 | 186 | if (_tableViewDataSource) { 187 | [self.tableView reloadData]; 188 | } 189 | } 190 | 191 | - (void)setMapViewDelegate:(id)mapViewDelegate 192 | { 193 | _mapViewDelegate = mapViewDelegate; 194 | self.mapView.delegate = _mapViewDelegate; 195 | } 196 | 197 | - (void)setTableView:(UITableView *)tableView 198 | { 199 | _tableView = tableView; 200 | 201 | if ([self.delegate respondsToSelector:@selector(locationPicker:tableViewDidLoad:)]) { 202 | [self.delegate locationPicker:self tableViewDidLoad:self.tableView]; 203 | } 204 | 205 | if (self.tableViewDidLoadBlock) { 206 | self.tableViewDidLoadBlock(self); 207 | } 208 | } 209 | 210 | - (void)setMapView:(MKMapView *)mapView 211 | { 212 | _mapView = mapView; 213 | 214 | if ([self.delegate respondsToSelector:@selector(locationPicker:mapViewDidLoad:)]) { 215 | [self.delegate locationPicker:self mapViewDidLoad:self.mapView]; 216 | } 217 | 218 | if (self.mapViewDidLoadBlock) { 219 | self.mapViewDidLoadBlock(self); 220 | } 221 | } 222 | 223 | - (void)setCustomCloseButton:(UIButton *)closeButton 224 | { 225 | [self setCustomCloseButton:closeButton atPoint:self.closeButtonPoint]; 226 | } 227 | 228 | - (void)setCustomCloseButton:(UIButton *)closeButton atPoint:(CGPoint)buttonPoint{ 229 | if(self.closeMapButton) [self.closeMapButton removeFromSuperview]; 230 | self.closeMapButton = closeButton; 231 | self.closeButtonPoint = buttonPoint; 232 | [self.closeMapButton addTarget:self action:@selector(didTapCloseMapViewButton:) forControlEvents:UIControlEventTouchUpInside]; 233 | self.closeMapButton.hidden = YES; 234 | 235 | [self insertSubview:self.closeMapButton aboveSubview:self.mapView]; 236 | } 237 | 238 | #pragma mark - Internal Methods 239 | 240 | - (void)mapWasTapped:(id)sender 241 | { 242 | [self expandMapView:self]; 243 | } 244 | 245 | - (void)showCloseMapButton 246 | { 247 | if (!self.closeMapButton) { 248 | self.closeMapButton = [UIButton buttonWithType:UIButtonTypeCustom]; 249 | self.closeMapButton.frame = CGRectMake(self.closeButtonPoint.x, self.closeButtonPoint.y, 42.0, 42.0); 250 | [self.closeMapButton setImage:[UIImage imageForXIcon] forState:UIControlStateNormal]; 251 | [self.closeMapButton setImage:[UIImage imageForXIcon] forState:UIControlStateHighlighted]; 252 | [self.closeMapButton addTarget:self action:@selector(didTapCloseMapViewButton:) forControlEvents:UIControlEventTouchUpInside]; 253 | self.closeMapButton.hidden = YES; 254 | 255 | [self insertSubview:self.closeMapButton aboveSubview:self.mapView]; 256 | } 257 | else{ 258 | [self.closeMapButton setFrame:CGRectMake(self.closeButtonPoint.x, self.closeButtonPoint.y, self.closeMapButton.frame.size.width, self.closeMapButton.frame.size.height)]; 259 | } 260 | 261 | self.closeMapButton.alpha = 0.0; 262 | self.closeMapButton.hidden = NO; 263 | [UIView animateWithDuration:0.3 264 | delay:0.0 265 | options:UIViewAnimationOptionCurveLinear 266 | animations:^{ 267 | self.closeMapButton.alpha = 1.0; 268 | } 269 | completion:nil]; 270 | } 271 | 272 | - (void)hideCloseMapButton 273 | { 274 | if (self.closeMapButton) { 275 | self.closeMapButton.hidden = NO; 276 | [UIView animateWithDuration:0.3 277 | delay:0.0 278 | options:UIViewAnimationOptionCurveLinear 279 | animations:^{ 280 | self.closeMapButton.alpha = 0.0; 281 | } 282 | completion:^(BOOL finished) { 283 | self.closeMapButton.hidden = YES; 284 | }]; 285 | } 286 | } 287 | 288 | #pragma mark - Expanding / Shrinking Map Methods 289 | 290 | - (void)expandMapView:(id)sender 291 | { 292 | [self expandMapView:sender animated:YES]; 293 | } 294 | 295 | - (void)expandMapView:(id)sender 296 | animated:(BOOL)animated 297 | { 298 | if ([self.delegate respondsToSelector:@selector(locationPicker:mapViewWillExpand:)]) { 299 | [self.delegate locationPicker:self mapViewWillExpand:self.mapView]; 300 | } 301 | if (self.mapViewWillExpand) { 302 | self.mapViewWillExpand(self); 303 | } 304 | 305 | self.isMapAnimating = animated; 306 | [self.tableView.tableHeaderView removeGestureRecognizer:self.mapTapGesture]; 307 | if (self.tableView.numberOfSections && [self.tableView numberOfRowsInSection:0]) { 308 | [self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated]; 309 | } 310 | 311 | CGRect newMapFrame = self.mapView.frame; 312 | newMapFrame = CGRectMake(self.defaultMapViewFrame.origin.x, 313 | self.defaultMapViewFrame.origin.y + (self.defaultMapHeight * self.parallaxScrollFactor), 314 | self.defaultMapViewFrame.size.width, 315 | self.defaultMapHeight + (self.defaultMapHeight * self.parallaxScrollFactor * 2)); 316 | self.mapView.frame = newMapFrame; 317 | 318 | [self bringSubviewToFront:self.mapView]; 319 | [self insertSubview:self.closeMapButton aboveSubview:self.mapView]; 320 | 321 | if(animated == YES) 322 | { 323 | [UIView animateWithDuration:0.3 324 | delay:0.0 325 | options:UIViewAnimationOptionCurveEaseOut 326 | animations:^{ 327 | self.mapView.frame = self.bounds; 328 | } completion:^(BOOL finished) { 329 | [self mapViewDidFinishExpanding]; 330 | }]; 331 | } 332 | else 333 | { 334 | self.mapView.frame = self.bounds; 335 | [self mapViewDidFinishExpanding]; 336 | } 337 | } 338 | 339 | - (void)mapViewDidFinishExpanding 340 | { 341 | self.isMapAnimating = NO; 342 | _isMapFullScreen = YES; 343 | self.mapView.scrollEnabled = YES; 344 | self.mapView.zoomEnabled = YES; 345 | 346 | [self centerMapOnUserLocationIfNecessary]; 347 | 348 | if ([self.delegate respondsToSelector:@selector(locationPicker:mapViewDidExpand:)]) { 349 | [self.delegate locationPicker:self mapViewDidExpand:self.mapView]; 350 | } 351 | if (self.mapViewDidExpand) { 352 | self.mapViewDidExpand(self); 353 | } 354 | 355 | if (self.shouldCreateHideMapButton) { 356 | [self showCloseMapButton]; 357 | } 358 | } 359 | 360 | - (void)hideMapView:(id)sender 361 | { 362 | [self hideMapView:sender animated:YES]; 363 | } 364 | 365 | - (void)didTapCloseMapViewButton:(id)sender 366 | { 367 | // override default close map button action if block is set 368 | if(self.mapCloseButtonTapped) 369 | { 370 | self.mapCloseButtonTapped(self); 371 | } 372 | else 373 | { 374 | // default action for close map view button 375 | [self hideMapView:self]; 376 | } 377 | } 378 | 379 | - (void)hideMapView:(id)sender animated:(BOOL)animated 380 | { 381 | if ([self.delegate respondsToSelector:@selector(locationPicker:mapViewWillBeHidden:)]) { 382 | [self.delegate locationPicker:self mapViewWillBeHidden:self.mapView]; 383 | } 384 | if (self.mapViewWillBeHidden) { 385 | self.mapViewWillBeHidden(self); 386 | } 387 | 388 | if (self.shouldCreateHideMapButton) { 389 | [self hideCloseMapButton]; 390 | } 391 | 392 | self.isMapAnimating = animated; 393 | self.mapView.scrollEnabled = NO; 394 | self.mapView.zoomEnabled = NO; 395 | [self.tableView.tableHeaderView addGestureRecognizer:self.mapTapGesture]; 396 | 397 | // Store the correct tableViewFrame. 398 | // Set table view off the bottom of the screen, and animate 399 | // back to normal 400 | CGRect tempFrame = self.tableView.frame; 401 | self.tableView.frame = CGRectMake(0, 480, tempFrame.size.width, tempFrame.size.height); 402 | [self insertSubview:self.mapView belowSubview:self.tableView]; 403 | 404 | if(animated == YES) 405 | { 406 | [UIView animateWithDuration:0.4 407 | delay:0.0 408 | options:UIViewAnimationOptionCurveEaseOut 409 | animations:^{ 410 | self.mapView.frame = self.defaultMapViewFrame; 411 | self.tableView.frame = tempFrame; 412 | } completion:^(BOOL finished) { 413 | [self mapViewDidFinishHiding]; 414 | }]; 415 | } 416 | else 417 | { 418 | self.mapView.frame = self.defaultMapViewFrame; 419 | self.tableView.frame = tempFrame; 420 | [self mapViewDidFinishHiding]; 421 | } 422 | } 423 | 424 | - (void)mapViewDidFinishHiding 425 | { 426 | [self insertSubview:self.closeMapButton aboveSubview:self.mapView]; 427 | self.isMapAnimating = NO; 428 | _isMapFullScreen = NO; 429 | 430 | [self centerMapOnUserLocationIfNecessary]; 431 | 432 | if ([self.delegate respondsToSelector:@selector(locationPicker:mapViewWasHidden:)]) { 433 | [self.delegate locationPicker:self mapViewWasHidden:self.mapView]; 434 | } 435 | if (self.mapViewWasHidden) { 436 | self.mapViewWasHidden(self); 437 | } 438 | } 439 | 440 | - (void)toggleMapView:(id)sender 441 | { 442 | if (!self.isMapAnimating) { 443 | if (self.isMapFullScreen) { 444 | [self hideMapView:self]; 445 | } 446 | else { 447 | [self expandMapView:self]; 448 | } 449 | } 450 | } 451 | 452 | - (void)centerMapOnUserLocationIfNecessary 453 | { 454 | if (self.shouldAutoCenterOnUserLocation && self.mapView.userTrackingMode) { 455 | MKCoordinateRegion centerCoordinate = MKCoordinateRegionMake(self.mapView.userLocation.coordinate, self.mapView.region.span); 456 | [self.mapView setRegion:centerCoordinate 457 | animated:YES]; 458 | } 459 | } 460 | 461 | #pragma mark - KVO Methods 462 | 463 | - (void)observeValueForKeyPath:(NSString *)keyPath 464 | ofObject:(id)object 465 | change:(NSDictionary *)change 466 | context:(void *)context 467 | { 468 | // Make sure we are observing this value. 469 | if (context != (__bridge void *)self) { 470 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 471 | return; 472 | } 473 | 474 | if ((object == self.tableView) && 475 | ([keyPath isEqualToString:@"contentOffset"] == YES)) { 476 | [self scrollViewDidScrollWithOffset:self.tableView.contentOffset.y]; 477 | } 478 | else if ((object == self.mapView) && 479 | ([keyPath isEqualToString:@"userTrackingMode"] == YES)) { 480 | } 481 | } 482 | 483 | - (void)scrollViewDidScrollWithOffset:(CGFloat)scrollOffset 484 | { 485 | if ((self.isMapFullScreen == NO) && 486 | (self.isMapAnimating == NO)) { 487 | CGFloat mapFrameYAdjustment = 0.0; 488 | 489 | // If the user is pulling down 490 | if (scrollOffset < 0) { 491 | 492 | // Pull to expand map? 493 | if (self.pullToExpandMapEnabled && 494 | (self.isMapAnimating == NO) && 495 | (scrollOffset <= -self.amountToScrollToFullScreenMap)) { 496 | [self expandMapView:self]; 497 | } 498 | else { 499 | mapFrameYAdjustment = self.defaultMapViewFrame.origin.y - (scrollOffset * self.parallaxScrollFactor); 500 | } 501 | } 502 | 503 | // If the user is scrolling normally, 504 | else { 505 | mapFrameYAdjustment = self.defaultMapViewFrame.origin.y - (scrollOffset * self.parallaxScrollFactor); 506 | 507 | // Don't move the map way off-screen 508 | if (mapFrameYAdjustment <= -(self.defaultMapViewFrame.size.height)) { 509 | mapFrameYAdjustment = -(self.defaultMapViewFrame.size.height); 510 | } 511 | } 512 | 513 | if (mapFrameYAdjustment) { 514 | CGRect newMapFrame = self.mapView.frame; 515 | newMapFrame.origin.y = mapFrameYAdjustment; 516 | self.mapView.frame = newMapFrame; 517 | } 518 | } 519 | } 520 | 521 | @end 522 | -------------------------------------------------------------------------------- /LocationPickerView/UIImage+Icons.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Icons.h 3 | // 4 | // Created by Christopher Constable on 5/10/13. 5 | // Copyright (c) 2013 Futura IO. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface UIImage (Icons) 11 | 12 | + (UIImage *)imageForXIcon; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LocationPickerView/UIImage+Icons.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Icons.m 3 | // 4 | // Created by Christopher Constable on 5/10/13. 5 | // Copyright (c) 2013 Futura IO. All rights reserved. 6 | // 7 | 8 | #import "UIImage+Icons.h" 9 | 10 | @implementation UIImage (Icons) 11 | 12 | + (UIImage *)imageForXIcon 13 | { 14 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(32, 32), NO, 0.0); 15 | CGContextRef context = UIGraphicsGetCurrentContext(); 16 | 17 | UIColor *strokeColor = [UIColor blackColor]; 18 | UIColor *shadowColor = [UIColor blackColor]; 19 | CGSize shadowOffset = CGSizeMake(1.0, 2.0); 20 | CGFloat shadowBlurRadius = 3.0; 21 | 22 | // Line 1 23 | UIBezierPath *bezierPath = [UIBezierPath bezierPath]; 24 | [bezierPath moveToPoint:CGPointMake(5, 5)]; 25 | [bezierPath addLineToPoint:CGPointMake(20, 20)]; 26 | bezierPath.miterLimit = 11; 27 | bezierPath.lineCapStyle = kCGLineCapRound; 28 | 29 | CGContextSaveGState(context); 30 | CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadowColor.CGColor); 31 | [strokeColor setStroke]; 32 | bezierPath.lineWidth = 5.0; 33 | [bezierPath stroke]; 34 | CGContextRestoreGState(context); 35 | 36 | // Line 2 37 | bezierPath = [UIBezierPath bezierPath]; 38 | [bezierPath moveToPoint:CGPointMake(5, 20)]; 39 | [bezierPath addLineToPoint:CGPointMake(20, 5)]; 40 | bezierPath.miterLimit = 11; 41 | bezierPath.lineCapStyle = kCGLineCapRound; 42 | 43 | CGContextSaveGState(context); 44 | CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadowColor.CGColor); 45 | [strokeColor setStroke]; 46 | bezierPath.lineWidth = 5.0; 47 | [bezierPath stroke]; 48 | CGContextRestoreGState(context); 49 | 50 | UIImage *returnImage = UIGraphicsGetImageFromCurrentImageContext(); 51 | UIGraphicsEndImageContext(); 52 | 53 | return returnImage; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LocationPickerView 2 | ============================ 3 | 4 | ### n.b. This repo is old and no longer maintained. I'm leaving it as-is in the hope that it may still be helpful or at the very least, a relic of the past. 5 | 6 | MKMapView + UITableView + Parallax scrolling. Provides a framework for building an interactive location picker on iOS. 7 | 8 | This view is useful for when a list of scrollable, selectable locations need to be shown along with their locations on map. A search bar can easily be added for searching or filtering. 9 | 10 |

11 | 12 |

13 | 14 | ## Install 15 | 16 | ### Cocoapods 17 | 18 | `pod 'LocationPickerView', '~> 1.2.0'` 19 | 20 | ### Manual 21 | 22 | Drop the **LocationPickerView** folder into your app. 23 | 24 | ## Usage 25 | 26 | In the view controlller you'd like to use the location picker in, add the following lines to `viewDidLoad`: 27 | 28 | ``` 29 | LocationPickerView *locationPickerView = [[LocationPickerView alloc] initWithFrame:self.view.bounds]; 30 | locationPickerView.tableViewDataSource = self; 31 | locationPickerView.tableViewDelegate = self; 32 | [self.view addSubview:self.locationPickerView]; 33 | ``` 34 | 35 | Alternatively, you can setup the `LocationPickerView` in a Storyboard. Just set the view's class to `LocationPickerView` 36 | 37 | ![](https://raw.github.com/mstrchrstphr/LocationPickerView/master/github-images/03.png) 38 | 39 | and be sure to hook up the table view delegate and datasource. 40 | 41 | ![](https://raw.github.com/mstrchrstphr/LocationPickerView/master/github-images/04.png) 42 | 43 | ## Advanced Usage 44 | 45 | If you want to get fancy you can specify more options: 46 | 47 | 48 | ``` 49 | // Create the location picker 50 | LocationPickerView *locationPickerView = [[LocationPickerView alloc] initWithFrame:self.view.bounds]; 51 | locationPickerView.tableViewDataSource = self; 52 | locationPickerView.tableViewDelegate = self; 53 | 54 | // Optional parameters 55 | locationPickerView.delegate = self; 56 | locationPickerView.shouldCreateHideMapButton = YES; 57 | locationPickerView.pullToExpandMapEnabled = YES; 58 | locationPickerView.defaultMapHeight = 190.0; 59 | locationPickerView.parallaxScrollFactor = 0.4; // little slower than normal. 60 | locationPickerView.backgroundViewColor = [UIColor yellowColor]; //set color to the tableView background without the map 61 | 62 | // Optional setup 63 | self.locationPickerView.mapViewDidLoadBlock = ^(LocationPickerView *locationPicker) { 64 | locationPicker.mapView.mapType = MKMapTypeStandard; 65 | }; 66 | self.locationPickerView.tableViewDidLoadBlock = ^(LocationPickerView *locationPicker) { 67 | locationPicker.tableView.separatorStyle = UITableViewCellSeparatorStyleSingleLine; 68 | }; 69 | 70 | [self.view addSubview:self.locationPickerView]; 71 | ``` 72 | 73 | Of particular use is the `delegate` property which allows you to know when important things are happening (like the map view is about to expand full screen). 74 | 75 | NOTE: Don't set the `backgroundColor` property of the table view. Color your cells or the `LocationPickerView` instead. 76 | 77 | ## Feature Wishlist 78 | 79 | * Add map annotations that sync with table view. 80 | * Add some basic search functionality. 81 | * Add more map controls (zooming, following user location, etc). 82 | 83 | ## Known Issues 84 | 85 | * Currently, deselecting a cell with animation doesn't look so good. You'll need to animate this yourself but hey, you can make it fancy! 86 | 87 | ## Contributing 88 | 89 | 1. Fork 90 | 2. Code 91 | 3. Comment :) 92 | 93 | ## License 94 | 95 | The MIT License Copyright (c) 2013 Christopher Constable 96 | -------------------------------------------------------------------------------- /github-images/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cconstable/LocationPickerView/4bce9ac0b5ad5780baa5bd6bca8d32bd58c699b9/github-images/03.png -------------------------------------------------------------------------------- /github-images/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cconstable/LocationPickerView/4bce9ac0b5ad5780baa5bd6bca8d32bd58c699b9/github-images/04.png -------------------------------------------------------------------------------- /github-images/location-picker.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cconstable/LocationPickerView/4bce9ac0b5ad5780baa5bd6bca8d32bd58c699b9/github-images/location-picker.gif --------------------------------------------------------------------------------