Don't re-add mapview after is loaded in viewdidload - ios

I have created function caricamappa() to loading map view with my mapbox map, and into Custompointannotation there is a control for add and remove annotation with Bool control, with a button i want to caricamappa() add and remove annotation with force Bool and its work but i don't want to re-add subview(mapview) into my app, is it possible to refresh a view without adding another and hide/show annotation? thanks
func carica_mappa() {
// Fill in the next line with your style URL from Mapbox Studio.
let styleURL = NSURL(string: "mapbox:***")
let mapView = MGLMapView(frame: view.bounds,
styleURL: styleURL as URL?)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Set the map’s center coordinate and zoom level.
mapView.setCenter(CLLocationCoordinate2D(latitude: 44.370417,
longitude: 7.411713),
zoomLevel: 13, animated: false)
view.addSubview(mapView)
mapView.userTrackingMode = .followWithHeading
// Set the delegate property of our map view to `self` after instantiating it.
mapView.delegate = self
let uno = CustomPointAnnotation(coordinate: CLLocationCoordinate2DMake(44.376362, 7.396907),
title: "**",
subtitle: "**",
controllo: visible)
// Set the custom `image` and `reuseIdentifier` properties, later used in the `mapView:imageForAnnotation:` delegate method.
uno.reuseIdentifier = "montagna"
uno.image = UIImage(named: "montagna")
if uno.controllo == true {
mapView.addAnnotation(uno)
}
else {
mapView.removeAnnotation(uno)
}
}
func mapView(_ mapView: MGLMapView, imageFor annotation: MGLAnnotation) -> MGLAnnotationImage? {
if let point = annotation as? CustomPointAnnotation,
let image = point.image,
let reuseIdentifier = point.reuseIdentifier {
if let annotationImage = mapView.dequeueReusableAnnotationImage(withIdentifier: reuseIdentifier) {
// The annotatation image has already been cached, just reuse it.
return annotationImage
} else {
// Create a new annotation image.
return MGLAnnotationImage(image: image, reuseIdentifier: reuseIdentifier)
}
}
// Fallback to the default marker image.
return nil
}
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
// Always allow callouts to popup when annotations are tapped.
return true
}
override func viewDidLoad() {
super.viewDidLoad()
carica_mappa()
}

My advice is to split the code to setup the map and the one to add the CustomAnnotationView. CaricaMappa() should only be used to add the map to its superview and called in viewDidLoad(). The code to setup the CustomAnnotation should be in its own method and you can call it on button tap. So you would have something like:
func carica_mappa() {
// Fill in the next line with your style URL from Mapbox Studio.
let styleURL = NSURL(string: "mapbox:***")
let mapView = MGLMapView(frame: view.bounds,
styleURL: styleURL as URL?)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Set the map’s center coordinate and zoom level.
mapView.setCenter(CLLocationCoordinate2D(latitude: 44.370417,
longitude: 7.411713),
zoomLevel: 13, animated: false)
view.addSubview(mapView)
mapView.userTrackingMode = .followWithHeading
// Set the delegate property of our map view to `self` after instantiating it.
mapView.delegate = self
}
#IBaction func didPressButton(sender: UIButton) {
let uno = CustomPointAnnotation(coordinate: CLLocationCoordinate2DMake(44.376362, 7.396907),
title: "**",
subtitle: "**",
controllo: visible)
// Set the custom `image` and `reuseIdentifier` properties, later used in the `mapView:imageForAnnotation:` delegate method.
uno.reuseIdentifier = "montagna"
uno.image = UIImage(named: "montagna")
if uno.controllo == true {
mapView.addAnnotation(uno)
}
else {
//You might want to check if the annotation exist in the map first.
mapView.removeAnnotation(uno)
}
}

Related

Disappearing markers during clustering in MapKit [duplicate]

I have an array of latitudes and another array of longitudes that I add to an array of type CLLocationCoordinate2D. I then use the new array to annotate multiple points on the map. Some, or most, or maybe even all of the annotations are displaying on the map but as I zoom in (yes, zoom IN), some of the annotations disappear, then come back, or dont. Any ideas on how to keep them all visible? This is behavior I would expect while zooming out, not in.
Here is the code i'm using for what i've described above.
import UIKit
import MapKit
import CoreLocation
class MultiMapVC: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var multiEventMap: MKMapView!
var latDouble = Double()
var longDouble = Double()
let manager = CLLocationManager()
var receivedArrayOfLats = [Double]()
var receivedArrayOfLongs = [Double]()
var locations = [CLLocationCoordinate2D]()
func locationManager(_ manager: CLLocationManager, didUpdateLocations uLocation: [CLLocation]) {
let userLocation = uLocation[0]
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.3, 0.3)
let usersLocation = userLocation.coordinate
let region:MKCoordinateRegion = MKCoordinateRegionMake(usersLocation, span)
multiEventMap.setRegion(region, animated: true)
manager.distanceFilter = 1000
self.multiEventMap.showsUserLocation = true
}
func multiPoint() {
var coordinateArray: [CLLocationCoordinate2D] = []
print ("Received Longitude Count = \(receivedArrayOfLongs.count)")
print ("Received Latitude Count = \(receivedArrayOfLats.count)")
if receivedArrayOfLats.count == receivedArrayOfLongs.count {
for i in 0 ..< receivedArrayOfLats.count {
let eventLocation = CLLocationCoordinate2DMake(receivedArrayOfLats[i], receivedArrayOfLongs[i])
coordinateArray.append(eventLocation)
print (coordinateArray.count)
}
}
for events in coordinateArray {
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: events.latitude, longitude: events.longitude)
multiEventMap.addAnnotation(annotation)
}
}
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
multiPoint()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
multiEventMap.removeFromSuperview()
self.multiEventMap = nil
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
NiltiakSivad's solution works but it reverts to the old iOS 10 look. If you want to keep the new iOS 11 balloon markers for iOS 11 and use the old pin look only for older iOS versions then you can implement the delegate method as below:
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let reuseIdentifier = "annotationView"
var view = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier)
if #available(iOS 11.0, *) {
if view == nil {
view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
}
view?.displayPriority = .required
} else {
if view == nil {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
}
}
view?.annotation = annotation
view?.canShowCallout = true
return view
}
The accepted answer from Leszek Szary is correct.
But there is some fineprint. Sometimes MKMarkerAnnotationViews are not rendered, even if
view.displayPriority = .required
is set.
What you are seeing is a combination of different rules.
MKAnnotationViews are rendered from top to bottom of the map. (It doesn't matter where north is).
If MapKit decides to draw overlapping MKAnnotationViews, then the MKAnnotationView nearer to the bottom is drawn on top (because it's drawn later)
Not only MKAnnotationViews, also titles rendered below MKMArkerAnnotationViews need space. The rendering of those titles is influenced by markerView.titleVisibility. If markerView.titleVisibility is set to .visible (instead of the default .adaptive), then this title is stronger than a MarkerAnnotationView that is rendered later, even if the later MarkerAnnotationView has a displayPriority = .required. The MarkerAnnotationView nearer to the bottom is not rendered.
This even happens if the MarkerAnnotationView nearer to the top has a low displayPriority. So a MarkerAnnotationView with low displayPriority and .titleVisibility = .visible can make a MarkerAnnotationView nearer to the bottom with displayPriority = .required disappear.
I am not aware of a documentation of this behaviour. This is the result of my experiments with iOS 12. My description is sipmplified.
I was experiencing a similar issue. My best guess is that it has something to do with how iOS 11 detects pin collisions. Implementing a custom annotation view or reverting to use the iOS 10 pin fixed the problem for me.
For example, implementing the following should fix your code:
class MultiMapVC: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard let annotation = annotation as? MKPointAnnotation else { return nil }
let identifier = "pin-marker"
var view: MKAnnotationView
if let dequeuedView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView {
dequeuedView.annotation = annotation
view = dequeuedView
} else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
}
return view
}
}
If this doesn't work, there is a displayPriority property that is worth looking into as it is responsible for helping to determine when pins should be hidden/shown at different zoom levels. More info at https://developer.apple.com/documentation/mapkit/mkannotationview/2867298-displaypriority
Hope this helps.
I was setting annotationView.displayPriority = .required only when the MKMarkAnnotationView was first allocated. Normally thats all you should need to do, but setting it each time the cell was reused fixed the issue for me.
I was seeing a similar problem with Xcode 10, and iOS 12+ as my deployment target. A post from an Apple staffer (https://forums.developer.apple.com/thread/92839) recommends toggling the .isHidden property on the dequeued marker. That has improved things but has not completely solved the problem.
result?.isHidden = true
result?.isHidden = false
return result

Custom MGLAnnotationView using Mapbox for IOS

I am very confused why this is displaying the default image instead of a round blue circle over New York. Any insight about this as well as when the default image is used will be greatly appreciated.
import UIKit
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setupMapview()
}
func setupMapview(){
let mapView = MGLMapView(frame: view.bounds)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.setCenter(CLLocationCoordinate2D(latitude: 40.74699, longitude: -73.98742), zoomLevel: 9, animated: false)
view.addSubview(mapView)
let annotation = MGLPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: 40.77014, longitude: -73.97480)
mapView.addAnnotation(annotation)
mapView.delegate = self
}
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
print("CORDINATE")
print(annotation.coordinate)
if annotation is MGLPointAnnotation {
print("SET\n\n\n")
let av = RoundedAnnotationView(annotation: annotation, reuseIdentifier: "ResuseIdentifier")
av.configure()
return av
}
return nil
}
}
class RoundedAnnotationView: MGLAnnotationView{
func configure(){
backgroundColor = .blue
layer.cornerRadius = 24
clipsToBounds = true
}
}
Output:
iPhone_Screen
print_statements
The standard default annotation is being shown in NY because that is exactly what you are adding to the map in setupMapview. If you want the map to display the user's location, you have to tell it to do so:
mapView.addAnnotation(annotation)
mapView.showsUserLocation = true // This needs to be set explicitly.
mapView.delegate = self
As usual, when you want to have access to the user's location you have to ask permission by inserting the correct flag in the info.plist:
Privacy - Location When In Use Usage Description
along with some kind of explanatory string:
"We'd like to track you with our satellite."
If you are running your app on the simulator you can create a custom location:
Simulator -> Features -> Location -> Custom Location...
Annotations should be added after the map has completely loaded. I have a more detailed step by step solution: https://github.com/mapbox/mapbox-gl-native/issues/16492

Swift -How to Update Data in Custom MKAnnotation Callout?

I have a custom annotation for my mapView. I initially set the coordinate, title (eg. "first title"), subTitle (eg. "first address"), userId, and a distance (eg. 0 meters) property on it with some data. I add it to the mapView and to an array for later use. Everything works, it shows on the mapView, I press it and the callout shows that initial data.
I later get updated that the location for that callout has changed. I loop through the array and update the callout with new data for the coordinate, title (eg. "new title"), subTitle (eg. "new address"), and distance (eg. 100 meters) properties. I also animate the callout from it's original location to it's new location. The animation works fine and the callout moves from point A to point B.
The problem is when I tap the annotation the old data gets shown on the callout instead of the new data.
I use calloutAccessoryControlTapped to push on a new vc. When i put a breakpoint there the custom pin has all the new data. The error seems to happen with the callout.
How do I fix this?
I don't want to clear all the annotations from the mapView so that's not an option. I call mapView.removeAnnotation(customPin) and mapView.addAnnotation(customPin) which fixes the problem for that pin but there is a blink when the pin is removed and added back to the map and then when it animates to it's new location it looks choppy.
Custom Annotation
class CustomPin: NSObject, MKAnnotation {
#objc dynamic var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
var userId: String?
var distance: CLLocationDistance?
init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String, userId: String, distance: CLLocationDistance?) {
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
self.userId = userId
self.distance = distance
super.init()
}
}
First time the annotation gets set with initial data
firstFunctionThatGetsTheInitialLocation(origLat, origLon) {
let firstCoordinate = CLLocationCoordinate2DMake(origLat, origLon)
let distanceInMeters: CLLocationDistance = self.center.distance(from: anotherUsersLocation)
let customPin = CustomPin(coordinate: firstCoordinate, title: "first title", subtitle: "first address", userId: "12345", distance: distance)
DispatchQueue.main.async { [weak self] in
self?.mapView.addAnnotation(customPin)
self?.arrOfPins.append(customPin)
}
}
Second time the annotation gets set with New Data
secondFunctionThatGetsTheNewLocation(newCoordinate: CLLocationCoordinate2D, newDistance: CLLocationDistance) {
for pin in customPins {
pin.title = "second title" // ** updates but the callout doesn't reflect it
pin.subTitle = "second address" // ** updates but the callout doesn't reflect it
pin.distance = newDistance // ** updates but the callout doesn't reflect it
// calling these gives me the new data but the annotation blinks and moves really fast to it's new location
// mapView.removeAnnotation(pin)
// mapView.addAnnotation(pin)
UIView.animate(withDuration: 1) {
pin.coordinate = newCoordinate // this updates and animates to the new location with no problem
}
}
}
MapView viewFor annotation
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation.isKind(of: MKUserLocation.self) { return nil }
guard let annotation = annotation as? CustomPin else { return nil }
let reuseIdentifier = "CustomPin"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: reuseIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
annotationView?.canShowCallout = true
annotationView?.calloutOffset = CGPoint(x: -5, y: 5)
annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
annotationView?.image = UIImage(named: "chevronImage")
} else {
annotationView?.annotation = annotation
}
annotationView?.detailCalloutAccessoryView = nil
annotationView?.detailCalloutAccessoryView = createCallOutWithDataFrom(customPin: annotation)
return annotationView
}
Creation of UIView for Callout
func createCallOutWithDataFrom(customPin: CustomPin) -> UIView {
let titleText = customPin.title
let subTitleText = customPin.subTitle
let distanceText = subTitle.distance // gets converted to a string
// 1. create a UIView
// 2. create some labels and add the text from the title, subTitle, and distance and add them as subViews to the UIView
// 3. return the UIView
}
There are a few issues:
You need to use the #objc dynamic qualifier for any properties you want to observe. The standard callout performs Key-Value Observation (KVO) on title and subtitle. (And the annotation view observes changes to coordinate.)
If you want to observe userid and distance, you have to make those #objc dynamic as well. Note, you’ll have to make distance be non-optional to make that observable:
var distance: CLLocationDistance
So:
class CustomAnnotation: NSObject, MKAnnotation {
// standard MKAnnotation properties
#objc dynamic var coordinate: CLLocationCoordinate2D
#objc dynamic var title: String?
#objc dynamic var subtitle: String?
// additional custom properties
#objc dynamic var userId: String
#objc dynamic var distance: CLLocationDistance
init(coordinate: CLLocationCoordinate2D, title: String, subtitle: String, userId: String, distance: CLLocationDistance) {
self.userId = userId
self.distance = distance
self.coordinate = coordinate
self.title = title
self.subtitle = subtitle
super.init()
}
}
Like I said, the standard callout observes title and subtitle. While you have to make the annotation properties observable, if you’re going to build your own detailCalloutAccessoryView, you’re going to have to do your own KVO:
class CustomAnnotationView: MKMarkerAnnotationView {
private let customClusteringIdentifier = "..."
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
canShowCallout = true
detailCalloutAccessoryView = createCallOutWithDataFrom(customAnnotation: annotation as? CustomAnnotation)
clusteringIdentifier = customClusteringIdentifier
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
removeAnyObservers()
}
override var annotation: MKAnnotation? {
didSet {
removeAnyObservers()
clusteringIdentifier = customClusteringIdentifier
if let customAnnotation = annotation as? CustomAnnotation {
updateAndAddObservers(for: customAnnotation)
}
}
}
private var subtitleObserver: NSKeyValueObservation?
private var userObserver: NSKeyValueObservation?
private var distanceObserver: NSKeyValueObservation?
private let subtitleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let userLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
private let distanceLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
}
private extension CustomAnnotationView {
func updateAndAddObservers(for customAnnotation: CustomAnnotation) {
subtitleLabel.text = customAnnotation.subtitle
subtitleObserver = customAnnotation.observe(\.subtitle) { [weak self] customAnnotation, _ in
self?.subtitleLabel.text = customAnnotation.subtitle
}
userLabel.text = customAnnotation.userId
userObserver = customAnnotation.observe(\.userId) { [weak self] customAnnotation, _ in
self?.userLabel.text = customAnnotation.userId
}
distanceLabel.text = "\(customAnnotation.distance) meters"
distanceObserver = customAnnotation.observe(\.distance) { [weak self] customAnnotation, _ in
self?.distanceLabel.text = "\(customAnnotation.distance) meters"
}
}
func removeAnyObservers() {
subtitleObserver = nil
userObserver = nil
distanceObserver = nil
}
func createCallOutWithDataFrom(customAnnotation: CustomAnnotation?) -> UIView {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(subtitleLabel)
view.addSubview(userLabel)
view.addSubview(distanceLabel)
NSLayoutConstraint.activate([
subtitleLabel.topAnchor.constraint(equalTo: view.topAnchor),
subtitleLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor),
subtitleLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor),
subtitleLabel.bottomAnchor.constraint(equalTo: userLabel.topAnchor),
userLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor),
userLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor),
userLabel.bottomAnchor.constraint(equalTo: distanceLabel.topAnchor),
distanceLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor),
distanceLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor),
distanceLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
if let customAnnotation = customAnnotation {
updateAndAddObservers(for: customAnnotation)
}
return view
}
}
That yields:

Can someone create a prepare for segue to move the map to another View Controller in this code?

I've been trying to code in swift a prepare for segue or to push view controller in order to move a map with a pin i have in a View Controller to another View Controller but in a smaller version. If someone can give an example on how to do it with this code, you would be very helpful.
I've been trying to do this in this function, so that when the user clears the pin title it goes to the other view controller with that same map:
if control == annotationView.rightCalloutAccessoryView {
print("Disclosure Pressed!")
}
Here's the complete code for this View Controller.
import UIKit
import MapKit
protocol HandleMapSearch {
func dropPinZoomIn(placemark:MKPlacemark)
}
class ViewController: UIViewController {
let locationManager = CLLocationManager()
var resultSearchController:UISearchController? = nil
var selectedPin:MKPlacemark? = nil
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
//
let locationSearchTable = storyboard!.instantiateViewControllerWithIdentifier("LocationSearchTable") as! LocationSearchTable
resultSearchController = UISearchController(searchResultsController: locationSearchTable)
resultSearchController?.searchResultsUpdater = locationSearchTable
//
let searchBar = resultSearchController!.searchBar
searchBar.sizeToFit()
searchBar.placeholder = "Search for places"
navigationItem.titleView = resultSearchController?.searchBar
//
resultSearchController?.hidesNavigationBarDuringPresentation = false
resultSearchController?.dimsBackgroundDuringPresentation = true
definesPresentationContext = true
//
locationSearchTable.mapView = mapView
//
locationSearchTable.handleMapSearchDelegate = self
//
let button = UIButton(type: UIButtonType.System) as UIButton
button.frame = CGRectMake(100, 100, 100, 50)
button.backgroundColor = UIColor.greenColor()
button.setTitle("Button", forState: UIControlState.Normal)
button.addTarget(self, action: Selector("Action:"), forControlEvents: UIControlEvents.TouchUpInside)
self.view.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
extension ViewController : CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedWhenInUse {
locationManager.requestLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.setRegion(region, animated: true)
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("error:: \(error)")
}
}
extension ViewController: HandleMapSearch {
func dropPinZoomIn(placemark:MKPlacemark){
// cache the pin
selectedPin = placemark
// clear existing pins
mapView.removeAnnotations(mapView.annotations)
let annotation = MKPointAnnotation()
annotation.coordinate = placemark.coordinate
annotation.title = placemark.name
if let city = placemark.locality,
let state = placemark.administrativeArea {
annotation.subtitle = "\(city) \(state)"
}
mapView.addAnnotation(annotation)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegionMake(placemark.coordinate, span)
mapView.setRegion(region, animated: true)
}
}
extension ViewController : MKMapViewDelegate {
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
//return nil so map view draws "blue dot" for standard user location
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView?.pinTintColor = UIColor.orangeColor()
pinView?.canShowCallout = true
pinView?.rightCalloutAccessoryView = UIButton(type: UIButtonType.DetailDisclosure) as UIButton
return pinView
}
func mapView(mapView: MKMapView, annotationView: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
if control == annotationView.rightCalloutAccessoryView {
print("Disclosure Pressed!")
}
}
}
In a word, no. Don't do that.
Trying to move views between view controllers is almost certainly the wrong way to do things.
It absolutely will not work to move a view (including a map view) from one view controller to another in prepareForSegue. The destination view controller's views haven't been loaded when prepareForSegue is called.
Instead, if you want to show a map in both your current view controller and the one to which you are segueing, you should define a map view in both view controllers, sized the way you want them in both places. You can then use prepareForSegue to tell the destination view controller the map region to display in it's map view. (Don't try to manipulate the destination view controller's map view from prepareForSegue. It won't work, and it's bad design even if you could make it work.)
Add a property mapRegion of type MKCoordinateRegion to the destination view controller. In the source view controller's prepareForSegue, get the map region of the current map and set the destination view controller's mapRegion property using that value.
Then, in the destination view controller's viewWillAppear:animated method, take the mapRegion property and used it to set the map view's region.
EDIT:
You also mentioned a pin. If you want the same pin to appear in both maps you should be able to fetch the MKAnnotation from the source view controller's map and pass it to the destination view controller, much like I described for setting the map region.

Taking code from UIViewController to UIView

I'm looking create this map inside a UIView. Would this be possible? If so can you tell me how I can take this code to a UIView from UIViewController. I'm trying to put a MapBox map into a UIView and there are only instructions on how to import it into a UIViewController
How would this code look as a UIView class:
import Mapbox
class mapboxMap: UIViewController, MGLMapViewDelegate {
var mapView: MGLMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView = MGLMapView(frame: view.bounds)
mapView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
// set the map's center coordinate
mapView.setCenterCoordinate(CLLocationCoordinate2D(latitude: 40.7326808,
longitude: -73.9843407),
zoomLevel: 10, animated: false)
view.addSubview(mapView)
// Set the delegate property of our map view to self after instantiating it.
mapView.delegate = self
// Declare the marker `hello` and set its coordinates, title, and subtitle
let hello = MGLPointAnnotation()
hello.coordinate = CLLocationCoordinate2D(latitude: 40.7326808, longitude: -73.9843407)
hello.title = "Hello world!"
hello.subtitle = "Welcome to my marker"
mapView.addAnnotation(hello)
let hello2 = MGLPointAnnotation()
hello2.coordinate = CLLocationCoordinate2D(latitude: 40.7526808, longitude: -73.9843407)
hello2.title = "Hello world!"
hello2.subtitle = "Welcome to my marker"
mapView.addAnnotation(hello2)
}
// Use the default marker; see our custom marker example for more information
func mapView(mapView: MGLMapView, imageForAnnotation annotation: MGLAnnotation) -> MGLAnnotationImage? {
return nil
}
func mapView(mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
override func viewDidAppear(animated: Bool) {
// Wait a bit before setting a new camera.
// Create a camera that rotates around the same center point, back to 0°.
// `fromDistance:` is meters above mean sea level that an eye would have to be in order to see what the map view is showing.
let camera = MGLMapCamera(lookingAtCenterCoordinate: mapView.centerCoordinate, fromDistance: 9000, pitch: 45, heading: 0)
// Animate the camera movement over 5 seconds.
mapView.setCamera(camera, withDuration: 2.5, animationTimingFunction: CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut))
}
}
I think what you are trying to do is "add UIViewController in subview". Try to use Container view Controller. And following thread may helpful to you.
add UIViewController in subview

Resources