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
Related
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
Hi everyone I've been working for a few days to show a straight line on my map. I use swiftUI and mapkit to render the map. what I want to achieve is a straight line between the two annotations, these are shown on the map.
Dit is de code die ik op dit moment heb. Ik hoop dut jullie mij kunnen helpen want ik kom er niet uit.
import MapKit
struct MapViewWorldDetail: UIViewRepresentable {
var StartCoordinate: CLLocationCoordinate2D
var EndCoordinate: CLLocationCoordinate2D
var name: String
#Binding var region: CLLocationCoordinate2D
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context) {
let span = MKCoordinateSpan(latitudeDelta: 50, longitudeDelta: 50)
let region = MKCoordinateRegion(center: self.region, span: span)
// view.mapType = MKMapType.satelliteFlyover;
view.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = StartCoordinate
annotation.title = name
view.addAnnotation(annotation)
let annotationEnd = MKPointAnnotation()
annotationEnd.coordinate = EndCoordinate
annotationEnd.title = name
view.addAnnotation(annotationEnd)
let aPolyline = MKGeodesicPolyline(coordinates: [StartCoordinate, EndCoordinate], count: 2)
view.addOverlay(aPolyline)
}
}
Note on the straight line you are drawing: The line that you are drawing using MKGeodesicPolyline has this note in the Apple Developer Documentation:
MKGeodesicPolyline - When displayed on a two-dimensional map view, the line segment between any two points may appear curved.
Example of working code
In SwiftUI, you'll need to implement the MKMapViewDelegate in a Coordinator class, which is where the Overlay handling is taken care of:
Add this to func updateUIView
func updateUIView(_ view: MKMapView, context: UIViewRepresentableContext<MapView>) {
// Stuff you already had in updateUIView
// :
// adding this at the end is sufficient
mapView.delegate = context.coordinator
}
Add this to your struct, struct MapViewWorldDetail
// MARK: - Coordinator for using UIKit inside SwiftUI.
func makeCoordinator() -> MapView.Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, MKMapViewDelegate {
var control: MapView
init(_ control: MapView) {
self.control = control
}
// MARK: - Managing the Display of Overlays
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
print("mapView(_:rendererFor:)")
if let polyline = overlay as? MKPolyline {
let polylineRenderer = MKPolylineRenderer(overlay: polyline)
polylineRenderer.strokeColor = .red
polylineRenderer.lineWidth = 3
return polylineRenderer
}
return MKOverlayRenderer(overlay: overlay)
}
}
Good references to review:
Sample project that implements the Coordinator class & delegates (but does not do overlays)
https://github.com/roblabs/ios-map-ui/tree/master/MapKit-SwiftUI-for-iOS-macOS
Medium posts by others
https://medium.com/better-programming/exploring-mapkit-on-ios-13-1a7a1439e3b6
https://medium.com/flawless-app-stories/mapkit-in-swiftui-c0cc2b07c28a
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)
}
}
I'm having a hard time figuring out how to make the annotation title appear when a user tapped an annotation pointed to the current location. Everything is working fine except this. I am using CLLocationManager wrapper from https://github.com/varshylmobile/LocationManager but I don't think it's affecting the Mapbox since I can display my pins correctly on the map.
Here's the screenshot sample:
As you can see, I could run the app without any problems. It's just when I set some annotation title and subtitle to the pin, and tapped it at run-time, it doesn't show anything.
Here's my code snippet for the annotation:
let point = MGLPointAnnotation()
point.coordinate = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
point.title = "Hello world!"
point.subtitle = "Welcome to The Ellipse."
self.mapView.addAnnotation(point)
let point2 = MGLPointAnnotation()
point2.coordinate = CLLocationCoordinate2D(latitude: 37.43259552, longitude: location.coordinate.longitude)
point2.title = "Hello world!"
point2.subtitle = "Welcome to The Ellipse."
self.mapView.addAnnotation(point2)
self.mapView.selectAnnotation(point, animated: true)
self.mapView.showAnnotations([point, point2], animated: true)
and here is the call out function:
func mapView(mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
func mapView(mapView: MGLMapView, imageForAnnotation annotation: MGLAnnotation) -> MGLAnnotationImage? {
return nil
}
I am on iOS 9.2, xCode 7.
Thank you!
I forgot this line of code after instantiating my map view.
mapView.delegate = self
Thanks!
Here's an example of how to configure basic callout views with the Mapbox iOS SDK:
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate {
var mapView: MGLMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView = MGLMapView(frame: view.bounds)
mapView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
view.addSubview(mapView)
// remember to set the delegate (or much of this will not work)
mapView.delegate = self
addAnnotation()
}
func addAnnotation() {
let annotation = MGLPointAnnotation()
annotation.coordinate = CLLocationCoordinate2DMake(35.03946, 135.72956)
annotation.title = "Kinkaku-ji"
annotation.subtitle = "\(annotation.coordinate.latitude), \(annotation.coordinate.longitude)"
mapView.addAnnotation(annotation)
// fit the map to the annotation(s)
mapView.showAnnotations(mapView.annotations!, animated: false)
// pop-up the callout view
mapView.selectAnnotation(annotation, animated: true)
}
func mapView(mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
func mapView(mapView: MGLMapView, leftCalloutAccessoryViewForAnnotation annotation: MGLAnnotation) -> UIView? {
if (annotation.title! == "Kinkaku-ji") {
let label = UILabel(frame: CGRectMake(0, 0, 60, 50))
label.textAlignment = .Right
label.textColor = UIColor(red: 0.81, green: 0.71, blue: 0.23, alpha: 1)
label.text = "金閣寺"
return label
}
return nil
}
func mapView(mapView: MGLMapView, rightCalloutAccessoryViewForAnnotation annotation: MGLAnnotation) -> UIView? {
return UIButton(type: .DetailDisclosure)
}
func mapView(mapView: MGLMapView, annotation: MGLAnnotation, calloutAccessoryControlTapped control: UIControl) {
// hide the callout view
mapView.deselectAnnotation(annotation, animated: false)
UIAlertView(title: annotation.title!!, message: "A lovely (if touristy) place.", delegate: nil, cancelButtonTitle: nil, otherButtonTitles: "OK").show()
}
}
I would like keep the MKAnnotaion on the centre of the screen when the user scoll the map like Careem app:
So far I managed to show the pin, update the pin position but when I scroll the map, the annotation in my code initially moves and then gets back to the centre. I would like the pin to remain on the centre.
#IBOutlet var mapView: MKMapView!
var centerAnnotation = MKPointAnnotation()
var manager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
manager = CLLocationManager() //instantiate
manager.delegate = self // set the delegate
manager.desiredAccuracy = kCLLocationAccuracyBest // required accurancy
manager.requestWhenInUseAuthorization() // request authorization
manager.startUpdatingLocation() //update location
var lat = manager.location.coordinate.latitude // get lat
var long = manager.location.coordinate.longitude // get long
var coordinate = CLLocationCoordinate2DMake(lat, long)// set coordinate
var latDelta:CLLocationDegrees = 0.01 // set delta
var longDelta:CLLocationDegrees = 0.01 // set long
var span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
var region:MKCoordinateRegion = MKCoordinateRegionMake(coordinate, span)
self.mapView.setRegion(region, animated: true)
centerAnnotation.coordinate = mapView.centerCoordinate
self.mapView.addAnnotation(centerAnnotation)
}
func mapView(mapView: MKMapView!, regionDidChangeAnimated animated: Bool) {
centerAnnotation.coordinate = mapView.centerCoordinate;
}
****UPDATE****
As suggested by Anna I have added a view to the map. Here the code:
var newPoint = self.mapView.convertCoordinate(mapView.centerCoordinate, toPointToView: self.view)
var pinImage = UIImage(named: "yoga_pins.png")
var imageView = UIImageView(image: pinImage) // set as you want
imageView.image = pinImage
imageView.backgroundColor = UIColor.clearColor()
imageView.contentMode = UIViewContentMode.Center
imageView.center.y = newPoint.y
imageView.center.x = newPoint.x
self.view.addSubview(imageView)
the only problem is that when the map is loaded the first time, the annotation which is located on the mapView.centerCoordinate and I am gonna use to get the latitude and longitude:
when I then scroll the map, the pin moves in the correct position (under the image):
func mapView(mapView: MKMapView!, regionDidChangeAnimated animated: Bool) {
centerAnnotation.coordinate = mapView.centerCoordinate;
}
I recommend you DSCenterPinMapView
It is a custom MapView with an animated and customizable center pin useful for selecting locations in map.
You should install the Pod and then, as a solution to your question you should implement the delegate so that you can get the location where pin drops.
pinMapView.delegate = self
extension MyViewController: DSCenterPinMapViewDelegate {
func didStartDragging() {
// My custom actions
}
func didEndDragging() {
// My custom actions
selectedLocation = pinMapView.mapview.centerCoordinate
}
}
You can use custom button. Add that button on centre of the map. Just show and hide that button according to your conditions.
So when you move map that button stay on same position that is centre of the map.