ProMotion-map
ProMotion-map provides a PM::MapScreen, extracted from the popular RubyMotion gem ProMotion.
Installation
gem 'ProMotion-map'
Usage
Easily create a map screen, complete with annotations.
Has all the methods of PM::Screen
class MyMapScreen < PM::MapScreen
title "My Map"
start_position latitude: 35.090648651123, longitude: -82.965972900391, radius: 4
tap_to_add
def annotation_data
[{
longitude: -82.965972900391,
latitude: 35.090648651123,
title: "Rainbow Falls",
subtitle: "Nantahala National Forest",
action: :show_forest,
pin_color: :green
},{
longitude: -82.966093558105,
latitude: 35.092520895652,
title: "Turtleback Falls",
subtitle: "Nantahala National Forest",
action: :show_forest,
pin_color: MKPinAnnotationColorPurple
},{
longitude: -82.95916,
latitude: 35.07496,
title: "Windy Falls",
action: :show_forest
},{
longitude: -82.943031505056,
latitude: 35.102516828489,
title: "Upper Bearwallow Falls",
subtitle: "Gorges State Park",
action: :show_forest
},{
longitude: -82.956244328014,
latitude: 35.085548421623,
title: "Stairway Falls",
subtitle: "Gorges State Park",
your_param: "CustomWhatever",
action: :show_forest
}, {
coordinate: CLLocationCoordinate2DMake(35.090648651123, -82.965972900391)
title: "Rainbow Falls",
subtitle: "Nantahala National Forest",
image: UIImage.imageNamed("custom-pin"),
action: :show_forest
}]
end
def show_forest
selected = selected_annotations.first
# Do something with the selected annotation.
end
end
Here's a neat way to zoom into a specific marker in an animated fashion and then select the marker:
def zoom_to_marker(marker)
set_region region(coordinate: marker.coordinate, span: [0.05, 0.05])
select_annotation marker
end
Methods
annotation_data
Method that is called to get the map's annotation data and build the map. If you do not want any annotations, simply return an empty array.
All possible properties:
{
# REQUIRED -or- use :coordinate
longitude: -82.956244328014,
latitude: 35.085548421623,
# REQUIRED -or- use :longitude & :latitude
coordinate: CLLocationCoordinate2DMake(35.085548421623, -82.956244328014)
title: "Stairway Falls", # REQUIRED
subtitle: "Gorges State Park",
image: "my_custom_image",
pin_color: :red, # Defaults to :red. Other options are :green or :purple or any MKPinAnnotationColor
left_accessory: my_button,
right_accessory: my_other_button,
action: :my_action, # Overrides :right_accessory
action_button_type: UIButtonTypeContactAdd # Defaults to UIButtonTypeDetailDisclosure
}
You may pass whatever properties you want in the annotation hash, but (:longitude
&& :latitude
|| :coordinate
), and :title
are required.
Use :image
to specify a custom image. Pass in a string to conserve memory and it will be converted using UIImage.imageNamed(your_string)
. If you pass in a UIImage
, we'll use that, but keep in mind that there will be another unnecessary copy of the UIImage in memory.
Use :left_accessory
and :right_accessory
to specify a custom accessory, like a button.
You can access annotation data you've arbitrarily stored in the hash by calling annotation_instance.params[:your_param]
.
The :action
parameter specifies a method that should be run when the detail button is tapped on the annotation. It automatically adds a UIButtonTypeDetailDisclosure
button to the :left_accessory
. In your method you can find out which annotation's accessory was tapped by calling selected_annotations.first
.
update_annotation_data
Forces a reload of all the annotations
annotations
Returns an array of all the annotations.
center
Returns a CLLocation2D
instance with the center coordinates of the map.
center=(Float, longitude: Float, animated: Boolean)
Sets the center of the map. animated
property defaults to true
.
show_user_location
Shows the user's location on the map. Must be called in the view initialization sequence on will_appear
or after.
look_up_location(CLLocation) { |placemark, error| }
This method takes a CLLocation object and will return one to many CLPlacemark to represent nearby data.
iOS 8 Location Requirements
iOS 8 introduced stricter location services requirements. You are now required to add a few key/value pairs to the Info.plist
. Add these two lines to your Rakefile
(with your descriptions, obviously):
app.info_plist['NSLocationAlwaysUsageDescription'] = 'Description'
app.info_plist['NSLocationWhenInUseUsageDescription'] = 'Description'
Note: you need both keys to use get_once
, so it's probably best to just include both no matter what. See Apple's documentation on iOS 8 location services requirements for more information.
hide_user_location
Hides the user's location on the map.
showing_user_location?
Returns a Boolean
of whether or not the map view is currently showing the user's location.
user_location
Returns a CLLocation2D
object of the user's location or nil
if the user location is not being tracked
zoom_to_user(radius = 0.05, animated=true)
Zooms to the user's location. If the user's location is not currently being shown on the map, it will show it first. radius
is a CLLocationDegrees
of the latitude and longitude deltas. See Apple documentation for MKCoordinateSpan
for more information.
select_annotation(annotation, animated=true)
Selects a single annotation.
select_annotation_at(annotation_index, animated=true)
Selects a single annotation using the annotation at the index of your annotation_data
array.
selected_annotations
Returns an array of annotations that are selected. If no annotations are selected, returns nil
.
deselect_annotations(animated=false)
Deselects all selected annotations.
add_annotation(annotation)
Adds a new annotation to the map. Refer to annotation_data
(above) for hash properties.
add_annotations(annotations)
Adds more than one annotation at a time to the map.
clear_annotations
Removes all annotations from the MapScreen
.
zoom_to_fit_annotations(include_user:false)
Changes the zoom and center point of the MapScreen
to fit all the annotations. Passing include_user
as true
will cause the zoom to not only include the annotations from annotation_data
but also the user pin in the zoom region calculation.
set_region(region, animated=true)
Sets the region of the MapScreen
. region
should be an instance of MKCoordinateRegion
.
region(params)
Helper method to create an MKCoordinateRegion
. Expects a hash in the form of:
my_region = region({
coordinate:{
latitude: 35.0906,
longitude: -82.965
},
# span is the latitude and longitude delta
span: [0.5, 0.5]
})
Class Methods
start_position(latitude: Float, longitude: Float, radius: Float)
Class method to set the initial starting position of the MapScreen
.
class MyMapScreen < PM::MapScreen
start_position latitude: 36.10, longitude: -80.26, radius: 4
end
radius
is the zoom level of the map in miles (default: 10).
tap_to_add(length: Float, target: Object, action: Selector, annotation: Hash)
Lets a user long press the map to drop an annotation where they pressed.
Default values:
You can override any of these values. The annotation
parameter can take any options specified in the annotation documentation above except :latitude
, :longitude
, and :coordinate
.
length: 2.0,
target: self,
action: "gesture_drop_pin:",
annotation: {
title: "Dropped Pin",
animates_drop: true
}
Notifications
This feature posts two different NSNotificationCenter
notifications:
ProMotionMapWillAddPin: Fired the moment the long press gesture is recognized, before the pin is added.
ProMotionMapAddedPin: Fired after the pin has been added to the map.
Example:
# Simple Example
class MyMapScreen < PM::MapScreen
title "My Map Screen"
tap_to_add length: 1.5
def annotations
[]
end
end
# A More Complex Example
class MyMapScreen < PM::MapScreen
title "My Map Screen"
tap_to_add length: 1.5, annotation: {animates_drop: true, title: "A Cool New Pin"}
def annotations
[]
end
def will_appear
NSNotificationCenter.defaultCenter.addObserver(self, selector:"pin_adding:") , name:"ProMotionMapWillAddPin", object:nil)
NSNotificationCenter.defaultCenter.addObserver(self, selector:"pin_added:") , name:"ProMotionMapAddedPin", object:nil)
end
def will_disappear
NSNotificationCenter.defaultCenter.removeObserver(self)
end
def pin_adding(notification)
# We only want one pin on the map at a time
clear_annotations
end
def pin_added(notification)
# Once the pin is dropped we want to select it
select_annotation_at(0)
end
end
Delegate callbacks
These methods (if implemented in your MapScreen
) will be called when the corresponding MKMapViewDelegate
method is invoked:
def will_change_region(animated)
# Do something when the region will change
# The animated parameter is optional so you can also define it is simply:
# def will_change_region
# end
end
def on_change_region(animated)
# Do something when the region changed
# The animated parameter is optional so you can also define it is simply:
# def on_change_region
# end
end
CocoaTouch Property Convenience Methods
MKMapView
contains multiple property setters and getters that can be accessed in a more ruby-like syntax:
type # Returns a MKMapType
type = (MKMapType)new_type
zoom_enabled?
zoom_enabled = (bool)enabled
scroll_enabled?
scroll_enabled = (bool)enabled
pitch_enabled?
pitch_enabled = (bool)enabled
rotate_enabled?
rotate_enabled = (bool)enabled
Accessors
map
or mapview
Reference to the created UIMapView.
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Make some specs pass
- Push to the branch (
git push origin my-new-feature
) - Create new Pull Request