Multiple Mapkit Views - ios

I am new to Xcode and I am trying to show different locations in the MapView. I have been able to set up a MapView, set the coordinates and then link it to a button, that when pressed displays the map with a drop pin.
import UIKit
import MapKit
class ViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var MapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
var latitude:CLLocationDegrees = 54.104456
var longitude: CLLocationDegrees = -6.228926
var latDelta:CLLocationDegrees = 0.001
var longDelta:CLLocationDegrees = 0.001
var theSpan:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
var clubLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
var theRegion:MKCoordinateRegion = MKCoordinateRegionMake(clubLocation, theSpan)
self.MapView.setRegion(theRegion, animated: true)
var clubAnnotation = MKPointAnnotation()
clubAnnotation.coordinate = clubLocation
clubAnnotation.title = "Football"
self.MapView.addAnnotation(clubAnnotation)
}
}
This is the code I have so far and it works. I want to have multiple buttons that when pressed will show the map with the coordinates set for that location. I want to show only one location for each button on the map.
This might be easy but I am new to code and any help would be great.

You can add buttons from code or from storyboard, here is an example how to add them from code:
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton.buttonWithType(.System) as! UIButton
button.setTitle("football", forState: .Normal)
button.frame = CGRectMake(8, 8, 150, 30)
button.addTarget(self, action: Selector("showFootball:"), forControlEvents: .TouchUpInside)
self.view.addSubview(button)
}
and here is example callback:
func showFootball(sender: UIButton) {
var clubAnnotation = MKPointAnnotation()
clubAnnotation.coordinate = CLLocationCoordinate2DMake(latitude, longitude)
clubAnnotation.title = "Football"
let mw = MKMapView()
mw.removeAnnotations(mw.annotations)
mw.addAnnotation(clubAnnotation)
}
You can add several buttons with different callback using that approach, or you can create an array of locations and assign tags for buttons. Then you can create only one callback and get location based on sender button's tag

Related

Implementing a Google Map with UItableviewCell

I am trying to implement a google map inside a UItableviewCell component. The way I am doing this is to define a GMSMapView within the protoype cell, and then using the dequeueReusableCell method i'm configuring the map cell. However, any change i try to apply fails (such as adding markers, camera, zoom, etc.). Does anybody have any information about this issue?
Code reference:
class UITenderInfoMapCell: UITableViewCell {
#IBOutlet weak var view: UIView!
#IBOutlet weak var subView: GMSMapView!
override func awakeFromNib() {
super.awakeFromNib()
self.initMap()
}
/**
Init blank map when initializing a MapCell, waypoints, directions, etc can be loaded later.
**/
func initMap() {
let camera = GMSCameraPosition.camera(withLatitude: 1.285, longitude: 103.848, zoom: 12)
let mapView = GMSMapView.map(withFrame: .zero, camera: camera)
self.subView = mapView
}
Do following steps to add MapView to TableViewCell
Take one UIView in your custom Tableviewcell and give the class name as "GMSmapView" to that UIView
Make sure to connect delegate method of Mapview.
In your ViewController import "GoogleMaps" along with delegate "GMSMapViewDelegate".
Make outlet for MapView like this for your created TableViewCell:
import UIKit
import GoogleMaps
class MapviewTableViewCell: UITableViewCell {
#IBOutlet weak var mapviewObj: GMSMapView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Add Following code in "cellForRowAt"
let cell = tableviewObj.dequeueReusableCell(withIdentifier: "cell") as! MapviewTableViewCell
let marker = GMSMarker()
let lat = Double("13.063754")
let long = Double("80.24358699999993")
marker.position = CLLocationCoordinate2DMake(lat!,long!)
///View for Marker
let DynamicView = UIView(frame: CGRect(x:0, y:0, width:50, height:50))
DynamicView.backgroundColor = UIColor.clear
//Pin image view for Custom Marker
let imageView = UIImageView()
imageView.frame = CGRect(x:0, y:0, width:50, height:35)
imageView.image = UIImage(named:"LocationPin")
//Adding pin image to view for Custom Marker
DynamicView.addSubview(imageView)
UIGraphicsBeginImageContextWithOptions(DynamicView.frame.size, false, UIScreen.main.scale)
DynamicView.layer.render(in: UIGraphicsGetCurrentContext()!)
let imageConverted: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
marker.icon = imageConverted
marker.map = cell.mapviewObj
cell.mapviewObj.camera = GMSCameraPosition.camera(withTarget: marker.position, zoom: 11)
return cell
NOTE:Here I am giving this some extra code to add your custom marker using "DynamicView". If you dont want to add custom marker, you can skip those code. Also Dont forget to configure require settings for google maps from google developer account and add respective key to you appdelegate e.g.
let key = "keep you key here"
GMSServices.provideAPIKey(key)
I added an outlet for GMSMapView as you did, nothing more. I skipped your initMap() method.
And in ViewController cellForRowAt and it works fine for me.
let marker = GMSMarker(position: CLLocationCoordinate2D(latitude: 51.483682, longitude: -0.091991))
marker.map = cell?.subView
What was your issue exactly?

My annonation isn't visible when I add it in the viewDidLoad of my app

I am developing an app where the user has to mark a location on a map, and then save it. My app then archives it, and when the user wants to see that location, the app is supposed to retreive the location's coordinates, and add an annonation on the map if the coordinates exist. Here is the piece of code I created to display the information the user selected-
#IBOutlet var mapGestureRecognizer: UIGestureRecognizer!
var item: itemData?
// Item Outlets
#IBOutlet weak var itemInfoView: UIView!
#IBOutlet weak var itemNameTextField: UITextField!
#IBOutlet weak var itemDescriptionLabel: UITextView!
#IBOutlet weak var mapView: MKMapView!
// Item Location Outlets
#IBOutlet weak var itemLocationView: UIView!
#IBOutlet weak var itemLocationTextView: UITextView!
let dropPin = MKPointAnnotation()
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
// Data loading
itemNameTextField.delegate = self
itemDescriptionLabel.delegate = self
itemLocationTextView.delegate = self
// Press recognizer
func mapViewFunc(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "myAnnotationView")
// configure the view
return annotationView
}
if let item = item {
itemNameTextField.text = item.itemName
itemDescriptionLabel.text = item.itemDescription
itemLocationTextView.text = item.itemPlace
dropPin.coordinate = mapView.convert(item.mapPoint, toCoordinateFrom: mapView)
dropPin.title = "Location of \(item.itemName)"
mapView.addAnnotation(dropPin)
print("Set the location of item pin to \(String(describing: dropPin.coordinate))")
}
// Styles
itemInfoView.layer.cornerRadius = 3
itemInfoView.layer.shadowColor = UIColor(red:0/255.0, green:0/255.0, blue:0/255.0, alpha: 1.0).cgColor
itemInfoView.layer.shadowOffset = CGSize(width: 0, height: 1.75)
itemInfoView.layer.shadowRadius = 1.7
itemInfoView.layer.shadowOpacity = 0.45
itemLocationView.layer.cornerRadius = 3
itemLocationView.layer.shadowColor = UIColor(red:0/255.0, green:0/255.0, blue:0/255.0, alpha: 1.0).cgColor
itemLocationView.layer.shadowOffset = CGSize(width: 0, height: 1.75)
itemLocationView.layer.shadowRadius = 1.7
itemLocationView.layer.shadowOpacity = 0.45
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
let annotation = MKPointAnnotation()
//let point = mapView.convert(coordinate, toPointTo: overlayView)
func action(gestureRecognizer:UIGestureRecognizer){
if let item = item {
dropPin.coordinate = mapView.convert((item.mapPoint), toCoordinateFrom: mapView)
dropPin.title = "Location of \(item.itemName)"
mapView.addAnnotation(dropPin)
print("Set the location of item pin to \(String(describing: dropPin.coordinate))")
}
else {
let itemName = itemNameTextField.text
let touchPoint = gestureRecognizer.location(in: mapView)
let newCoordinates = mapView.convert(touchPoint, toCoordinateFrom: mapView)
annotation.coordinate = newCoordinates
annotation.title = "Location of \(itemName!)"
mapView.addAnnotation(annotation)
}
}
#IBAction func mapLocationPress(_ sender: UILongPressGestureRecognizer) {
action(gestureRecognizer: mapGestureRecognizer)
}
All the print statements I've created work, so I know that the app does save the coordinates, and that it does convert them properly. However, when the app loads the information in the if let item = item portion of the viewDidLoad, the pin isn't dropped onto the map like it's supposed to.
Does anybody see why my code isn't working the way it's supposed to? Thanks!
If you need my full code, tell me, and I will put it into my question.
You need to use
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "myAnnotationView")
// configure the view
return annotationView
}
outside your viewDidLoad() function
You should put mapViewFunc out of viewDidLoad, but if you want to leave it in viewDidLoad
try
func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.async {
// add pin
}
}

How to identify which GMSMarker was tapped - iOS, Swift

I'm quite new to Swift and i'm trying to better understand Google Maps API. I'm building a simple app that shows images when markers on panoramaView are tapped through didTapMarker method. Since each marker should show a different images, i'm trying to find a way to identify which marker has been tapped, a sort of marker tag.
All suggestions are welcome.
Down here is a prototype of the code with 2 markers and 2 images. Not really sure how to do it, but didTapMarker method should show randomImage when marker is tapped and randomImage2 when marker2 is tapped. So far it only shows randomImage when both marker and marker1 are tapped.
import UIKit
import GoogleMaps
class ViewController: UIViewController, GMSPanoramaViewDelegate {
#IBOutlet weak var viewStreet: UIView!
#IBOutlet weak var randomImage: UIImageView!
#IBOutlet weak var randomImage2: UIImageView!
var panoView: GMSPanoramaView!
override func viewDidLoad() {
super.viewDidLoad()
randomImage.hidden = true
randomImage2.hidden = true
let panoView = GMSPanoramaView(frame: CGRectMake(200, 200, 400, 400))
panoView.delegate = self
panoView.moveNearCoordinate(CLLocationCoordinate2D(latitude: -33.732, longitude: 150.312))
viewStreet.addSubview(panoView)
viewStreet.sendSubviewToBack(panoView)
let position = CLLocationCoordinate2D(latitude: -33.732, longitude: 150.312)
let marker = GMSMarker(position: position)
marker.panoramaView = panoView
let position2 = CLLocationCoordinate2D(latitude: -33.732, longitude: 150.311)
let marker2 = GMSMarker(position: position2)
marker2.panoramaView = panoView
}
func panoramaView(panoramaView: GMSPanoramaView, didTapMarker marker: GMSMarker) -> Bool {
randomImage.hidden = false
randomImage2.hidden = true
return true
}
}
EDIT: solved, thanks to everyone, i'm adding a trivial example on how to do it then.
marker.userData = "example"
Then didTapMarker method is always called when a marker is tapped, but randomImage 's propriety is set to false only when the marker tapped is the one above.
func panoramaView(panoramaView: GMSPanoramaView, didTapMarker marker: GMSMarker) -> Bool {
if marker.userData as? String == "example" {
randomImage.hidden = false
}
return true
}
Code can be improved making use of a dictionary to handle multiple markers but it's up to you. :)
put the data of that marker in userData of that marker. Make use of that that whenever marker is tapped in didTapInfoWindowOfMarker api.

Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) error occurs when getting the latitude and longitude

Please help me with this problem
import Foundation
import UIKit
import MapKit
class DetailViewController : UIViewController {
#IBOutlet weak var mapView: MKMapView!
var selectedLocation : LocationModel?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
// Create coordinates from location lat/long
var poiCoodinates: CLLocationCoordinate2D = CLLocationCoordinate2D()
poiCoodinates.latitude = CDouble(self.selectedLocation!.latitude!)! //Problem is in this line
poiCoodinates.longitude = CDouble(self.selectedLocation!.longitude!)!
// Zoom to region
let viewRegion: MKCoordinateRegion = MKCoordinateRegionMakeWithDistance(poiCoodinates, 750, 750)
self.mapView.setRegion(viewRegion, animated: true)
// Plot pin
let pin: MKPointAnnotation = MKPointAnnotation()
pin.coordinate = poiCoodinates
self.mapView.addAnnotation(pin)
//add title to the pin
pin.title = selectedLocation!.name
}
}
You have not initialised var selectedLocation : LocationModel? so when you ask for self.selectedLocation! it crash.
Add that needed initialisation and try to refactor your code in this
way:
override func viewDidAppear(animated: Bool) {
guard let location = self.selectedLocation, let latitude = location.latitude, let longitude = location.longitude else {
return //Here was an error, so you can not continue, report it or do something about it before returning
}
// Create coordinates from location lat/long
var poiCoodinates: CLLocationCoordinate2D = CLLocationCoordinate2D()
poiCoodinates.latitude = CDouble(latitude)!
poiCoodinates.longitude = CDouble(longitude)!
// Zoom to region
let viewRegion: MKCoordinateRegion = MKCoordinateRegionMakeWithDistance(poiCoodinates, 750, 750)
self.mapView.setRegion(viewRegion, animated: true)
// Plot pin
let pin: MKPointAnnotation = MKPointAnnotation()
pin.coordinate = poiCoodinates
self.mapView.addAnnotation(pin)
//add title to the pin
pin.title = location.name
}
I finally found the solution and here it goes:
import MapKit
class DetailViewController : UIViewController, MKMapViewDelegate {
//var mapType:UISegmentedControl!
//var showPointsOfInterest:UISwitch!
#IBOutlet weak var mapView: MKMapView!
#IBAction func showDirection(sender: AnyObject) {
}
var selectedLocation : LocationModel?
let locationManager = CLLocationManager()
var currentPlacemark:CLPlacemark?
//var segmentedControlAciton:UISegmentedControl!
#IBAction func myLocation(sender: AnyObject) {
// Request for a user's authorization for location services
locationManager.requestWhenInUseAuthorization()
let status = CLLocationManager.authorizationStatus()
if status == CLAuthorizationStatus.AuthorizedWhenInUse {
mapView.showsUserLocation = true
}
}
//
override func viewDidLoad() {
super.viewDidLoad()
// mapView.showsUserLocation = true
title = selectedLocation?.name
mapView.delegate = self
}
override func viewDidAppear(animated: Bool) {
// Create coordinates from location lat/long
var poiCoordinates: CLLocationCoordinate2D = CLLocationCoordinate2D()
poiCoordinates.latitude = CDouble(self.selectedLocation!.latitude!)!
poiCoordinates.longitude = CDouble(self.selectedLocation!.longitude!)!
// Zoom to region
let viewRegion: MKCoordinateRegion = MKCoordinateRegionMakeWithDistance(poiCoordinates, 750, 750)
self.mapView.setRegion(viewRegion, animated: true)
// Plot pin
let pin: MKPointAnnotation = MKPointAnnotation()
pin.coordinate = poiCoordinates
self.mapView.addAnnotation(pin)
//add title to the pin
pin.title = selectedLocation!.name
pin.subtitle=selectedLocation!.address
mapView.showsScale = true
}

Keep the pin (MKAnnotation) on the center when user scroll the map

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.

Resources