So, at the moment I can't seem to figure out how the user can enter a title on the Annotation pins. In my code a pin will appear after a long press on the map, but the title shown of the pin is "Pin".
The only thing I would like to be able to do is for the user of the app to be able to create unique titles of the pins on creation.
import Foundation
import UIKit
import MapKit
class MapsViewController: UIViewController, CLLocationManagerDelegate {
let locationManager:CLLocationManager = CLLocationManager()
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for currentLocation in locations{
print("\(index) : \(currentLocation)")
}
}
#IBAction func addPin(_ sender: UILongPressGestureRecognizer) {
let alert = UIAlertController(title: "Title", message: "Please enter location name", preferredStyle: .alert)
//2. Add the text field. You can configure it however you need.
alert.addTextField { (textField) in
textField.text = "Location name"
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
print("Text field: \(String(describing: textField?.text))")
DispatchQueue.main.async { self.addPinWithTitle (sender , title : textField?.text ?? "") }
}))
self.present(alert, animated: true, completion: nil)}
func addPinWithTitle(_ sender: UILongPressGestureRecognizer , title : String) {
let location = sender.location(in: self.mapView)
let locCoordinates = self.mapView.convert(location, toCoordinateFrom: self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = locCoordinates
annotation.title = title
self.mapView.addAnnotation(annotation)}
}
Please follow the final code
#IBAction func addPin(_ sender: UILongPressGestureRecognizer) {
let alert = UIAlertController(title: "Title", message: "Please enter location name", preferredStyle: .alert)
//2. Add the text field. You can configure it however you need.
alert.addTextField { (textField) in
textField.placeholder = "Location name"
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
print("Text field: \(textField?.text)")
DispatchQueue.main.async {
self.addPinWithTitle (sender , title : textField?.text ?? "")
}
}))
self.present(alert, animated: true, completion: nil)}
func addPinWithTitle(_ sender: UILongPressGestureRecognizer , title : String) {
let location = sender.location(in: self.mapView)
let locCoordinates = self.mapView.convert(location, toCoordinateFrom: self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = locCoordinates
annotation.title = title
self.mapView.addAnnotation(annotation)}
Related
I want to send the location messages using firebase. like when user click on button it shows alert which message you want to send like audio,video,location.When user select the location from the given option it will call locationViewController and store the location in firebase.I've simple loaded the google map with marker pin point and defined the coordinates it's self not dynamically. InputActionSheet func that defined in chatViewController when user tap on choose button this function call and inside another function call that will call the functionality of location messages.But I'm confused how we get get coordinates dynamically when user taped on any location on google map and also it will show the marker when user tap.
SimpleViewController class for checking the functionality of google map it's working fine:
class ViewController: UIViewController {
#IBOutlet weak var mapView: GMSMapView!
let manager = CLLocationManager()
let karachi = CLLocationCoordinate2D(latitude: 24.882752, longitude: 67.149848)
let tandoAdam = CLLocationCoordinate2D(latitude: 25.76284, longitude: 68.66087)
override func viewDidLoad() {
super.viewDidLoad()
self.setupMap(title: "Karachi", subtitle: "Shah Faisal", karachi)
self.setupMap(title: "TDM", subtitle: "AK H", tandoAdam)
self.mapView.mapStyle(name:"darkTheme", type:"json")
}
func setupMap(title:String,subtitle:String,_ coordinate:CLLocationCoordinate2D){
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
let camera = GMSCameraPosition.camera(withLatitude: coordinate.latitude, longitude: coordinate.longitude, zoom: 6.0)
mapView.camera = camera
mapView.camera = camera
self.addMarker(title: title, subtitle: subtitle, coordinate:coordinate)
}
func addMarker(title:String,subtitle:String,coordinate:CLLocationCoordinate2D){
let marker = GMSMarker()
marker.icon = #imageLiteral(resourceName: "DiceFive")
marker.position = coordinate
marker.title = title
marker.snippet = subtitle
marker.map = mapView
}
}
extension UIViewController : CLLocationManagerDelegate {
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard locations.first != nil else{
return
}
}
}
presentInputActionSheet func in Chat class:
private func presentInputActionSheet() {
let actionSheet = UIAlertController(title: "Attach Media",
message: "What would you like to attach?",
preferredStyle: .actionSheet)
actionSheet.addAction(UIAlertAction(title: "Photo", style: .default, handler: { [weak self] _ in
self?.presentPhotoInputActionsheet()
}))
actionSheet.addAction(UIAlertAction(title: "Video", style: .default, handler: { [weak self] _ in
self?.presentVideoInputActionsheet()
}))
actionSheet.addAction(UIAlertAction(title: "Audio", style: .default, handler: { _ in
}))
actionSheet.addAction(UIAlertAction(title: "Location", style: .default, handler: { [weak self] _ in
self?.presentLocationPicker()
}))
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(actionSheet, animated: true)
}
presentLocationPicker func in Chat class:
private func presentLocationPicker() {
let vc = ViewController(coordinates: nil)
vc.title = "Pick Location"
vc.navigationItem.largeTitleDisplayMode = .never
let location = Location(location: CLLocation(latitude: latitude, longitude: longitude),
size: .zero)
let message = Message(sender: selfSender,messageId: messageId,sentDate: Date(),kind: .location(location))
DatabaseManager.shared.sendMessage(to: conversationId, otherUserEmail: strongSelf.otherUserEmail, name: name, newMessage: message, completion: { success in
if success {
print("sent location message")
}
else {
print("failed to send location message")
}
})
}
navigationController?.pushViewController(vc, animated: true)
}
try this
let message = Message(sender: selfSender,messageId: messageId,sentDate: Date(),kind: .location(location))
DatabaseManager.shared.sendMessage(to: conversationId, otherUserEmail: strongSelf.otherUserEmail, name: name, newMessage: message, completion: { success in
if success {
print("sent location message")
}
else {
print("failed to send location message")
}
navigationController?.pushViewController(vc, animated: true)
})
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I tried to add an annotation in my map when I click the button. I have written some codes but I am not getting any annotation based on my current location.
#IBAction func addPressed(_ sender: Any) {
guard let location = self.locationManager.location else {
return
}
let annotation = MKPointAnnotation()
annotation.title = "Flooded"
annotation.subtitle = "Reported on 12/10/2018 8:50 AM"
annotation.coordinate = location.coordinate
self.mapView.addAnnotation(annotation)
}
Add this to your view controller and also make sure to assign delegate to self for mapView in viewDidLoad()
Update: As dicsussed in comments, replace your complete view controller code with the code below.
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var add: UIButton!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
checkLocationServices()
}
func setupLocationManager () {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
setupLocationManager()
checkLocationAuthorization()
} else {
}
}
func checkLocationAuthorization () {
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted:
let alert = UIAlertController(title: "Location Services disabled", message: "Please enable Location Services in Settings", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
return
case .denied:
let alert = UIAlertController(title: "Location Services disabled", message: "Please enable Location Services in Settings", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
return
case .authorizedAlways:
break
case .authorizedWhenInUse:
mapView.showsUserLocation = true // this will bring the blue dot on map
centreZoomviewUserLocation()
locationManager.startUpdatingLocation()
#unknown default:
break
}
}
func centreZoomviewUserLocation () {
if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: 10000, longitudinalMeters: 10000)
mapView.setRegion(region, animated: true)
}
}
//MARK:- Button pressed
#IBAction func addPressed(_ sender: Any) {
guard let location = self.locationManager.location else {
return
}
let annotation = MKPointAnnotation()
annotation.title = "Flooded"
annotation.subtitle = "Reported on 12/10/2018 8:50 AM"
annotation.coordinate = location.coordinate
DispatchQueue.main.async {
self.mapView.addAnnotation(annotation)
}
}
}
extension ViewController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let newPin = MKPointAnnotation()
guard let location = locations.last else { return }
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion.init(center: center, latitudinalMeters: 10000, longitudinalMeters: 10000)
mapView.setRegion(region, animated: true)
newPin.coordinate = location.coordinate
mapView.addAnnotation(newPin)
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationAuthorization()
}
}
extension ViewController : MKMapViewDelegate {
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard annotation is MKPointAnnotation else { return nil }
let identifier = "Annotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView!.canShowCallout = true
} else {
annotationView!.annotation = annotation
}
return annotationView
}
}
I'm trying to show my current location on simulator but it displays another location
import UIKit
import MapKit
class DriverVC: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var myMap: MKMapView!
let locationManager = CLLocationManager()
var driverLocation : CLLocationCoordinate2D?
var userLocation : CLLocationCoordinate2D?
override func viewDidLoad() {
super.viewDidLoad()
intializeLocationManager()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locationManager.location?.coordinate {
print("location\(location)")
myMap.removeAnnotations(myMap.annotations)
driverLocation = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
let region = MKCoordinateRegion(center: driverLocation!, span: MKCoordinateSpanMake(0.07, 0.07))
myMap.setRegion(region, animated: true)
let annotation = MKPointAnnotation()
annotation.coordinate = driverLocation!
annotation.title = "driver location"
myMap.addAnnotation(annotation)
}
}
private func intializeLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
#IBAction func signOut(_ sender: UIBarButtonItem) {
if (AuthProvider.Instance.logOut()){
dismiss(animated: true, completion: nil)
}
else{
alertTheUser(title: "couldn't sign out", message: "try again")
}
}
#IBAction func answer(_ sender: UIButton) {
}
private func alertTheUser(title: String, message: String){
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(ok)
present(alert,animated: true, completion: nil)
}
}
I added Location when in usage description to Info.plist and the simulator debug location is non
I had hardly tried few days ago to embed my current location in Message body on my iPhone, but I failed.
I tried all I have in my mind, but I only got errors
Last error I got is
"fatal error: unexpectedly found nil while unwrapping an Optional
value"
I created an object of CLPlacemark and I made it optional, which means it could have value or could have nil.
is there any way to create a message with my current location ?
MainMenu file
import UIKit
import Social
import MessageUI
import Foundation
import CoreLocation
class MainMenu: UIViewController , MFMessageComposeViewControllerDelegate , UINavigationControllerDelegate , MFMailComposeViewControllerDelegate, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
func messageComposeViewController(controller: MFMessageComposeViewController, didFinishWithResult result: MessageComposeResult) {
}
let placeMarks = Location()
#IBAction func TapOnEmergency(sender: UIButton) {
let textMessageRecipients = ["+123456789"]
let messageComposer = MFMessageComposeViewController()
let Emergency = UIAlertController(title: "Do You Need Help ?", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
let Yes = UIAlertAction(title: "YES", style: .Default) { (action) in
if (MFMessageComposeViewController.canSendText()) {
messageComposer.messageComposeDelegate = self
messageComposer.recipients = textMessageRecipients
messageComposer.body = "I'm Lost, I need some Help, Here's my Location \(self.placeMarks.currentLocation!.country)"
self.navigationController?.presentViewController(messageComposer, animated: true){}
self.presentViewController(messageComposer, animated: true, completion: nil)
self.messageComposeViewController(messageComposer, didFinishWithResult: MessageComposeResultCancelled)
} else {
let errorAlert = UIAlertController(title: "Cannot Send Text Message", message: "Your device is not able to send text messages.", preferredStyle: UIAlertControllerStyle.Alert)
errorAlert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil))
self.presentViewController(errorAlert, animated: true, completion: nil)
}
let Options = UIAlertController(title: "Do You Want to Call Your Supervisor ?", message: nil, preferredStyle: UIAlertControllerStyle.ActionSheet)
let dialNumber = UIAlertAction(title: "YES", style: .Default) { (action) in
let call:NSURL = NSURL(string: "tel://123456789")!
UIApplication.sharedApplication().openURL(call)
}
Options.addAction(dialNumber)
let Dismiss = UIAlertAction(title: "Dismiss", style: .Destructive) { (action) in
}
Options.addAction(Dismiss)
self.presentViewController(Options, animated: true) {}
}
Emergency.addAction(Yes)
let No = UIAlertAction(title: "Dismiss", style: .Destructive) { (action) in
}
Emergency.addAction(No)
self.presentViewController(Emergency, animated: true) {}
}
}
Location file
import UIKit
import CoreLocation
class Location: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var currentLocation : CLPlacemark?
}
Just creating CLPlacemark will not fetch location for you. You will have to create object of CLLocationManager and then update your current location using startUpdatingLocation method of CLLocationManager object. Also you'll have to implement delegate methods for receiving the current location this way.
import UIKit
import CoreLocation
class Location: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var currentLocation : CLPlacemark?
var locationManager = CLLocationManager()
private override init() {
super.init()
locationManager.delegate = self
}
func updateLocation()
{
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
locationManager.stopUpdatingLocation()
let location : CLLocation = locations.last as CLLocation!
//use reverse geocoding to get the address from location coordinates you got
}
}
Once you get location coordinates you can do reverse geocoding to get the place mark or exact address. Refer to Reverse Geocode Location in Swift for reverse geocoding. Regarding the error you are getting, you can check if place mark object is nil before creating a message.
I have a label named "direction". I have a map with a lot of pins. When i click on one pin and tap the label "direction" it give me two options and works fine. But when i do not click on a Pin and tap de label "direction" the app crash.
i want to setup an statement when the a pin is not selected an alert show that the user first select a pin to get directions.
Hope someone can look at code to make this possible:
import UIKit
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate, GMSMapViewDelegate {
#IBOutlet weak var mapView: GMSMapView!
#IBAction func MapType(sender: AnyObject) {
let segmentedControl = sender as! UISegmentedControl
switch segmentedControl.selectedSegmentIndex {
case 0:
mapView.mapType = kGMSTypeNormal
case 1:
mapView.mapType = kGMSTypeSatellite
case 2:
mapView.mapType = kGMSTypeHybrid
default:
mapView.mapType = mapView.mapType
}
}
let locationManager = CLLocationManager()
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
//3
mapView.delegate = self
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
var Marker= GMSMarker()
Marker.position = CLLocationCoordinate2DMake(5.2317, 4.5708 )
Marker.title = "1"
Marker.snippet = "1"
Marker.appearAnimation = kGMSMarkerAnimationPop
Marker.map = mapView
var Marker1= GMSMarker()
Marker1.position = CLLocationCoordinate2DMake(5.2317, 8.5708 )
Marker1.title = "2"
Marker1.snippet = "2"
Marker1.map = mapView
let label = UILabel(frame: CGRectMake(view.frame.size.width - 100, view.frame.size.height - 40, 80, 30))
label.backgroundColor = UIColor.whiteColor()
label.text = "direction"
label.textAlignment = .Center
label.layer.cornerRadius = 10
label.clipsToBounds = true
label.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "directionTapped")
label.addGestureRecognizer(tap)
mapView!.settings.consumesGesturesInView = false
mapView!.addSubview(label)
mapView!.bringSubviewToFront(label)
self.view.addSubview(label)
}
func directionTapped() {
let openMapsActionSheet = UIAlertController(title: "Open in Maps", message: "Choose a maps application", preferredStyle: .ActionSheet)
openMapsActionSheet.addAction(UIAlertAction(title: "Apple Maps", style: .Default, handler: { (action: UIAlertAction!) -> Void in
let placemark = MKPlacemark(coordinate: CLLocationCoordinate2DMake(self.mapView!.selectedMarker.position.latitude, self.mapView!.selectedMarker.position.longitude), addressDictionary: nil)
let item = MKMapItem(placemark: placemark)
let options = [MKLaunchOptionsDirectionsModeKey:
MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsShowsTrafficKey: true]
item.openInMapsWithLaunchOptions(options as [NSObject : AnyObject])
}))
openMapsActionSheet.addAction(UIAlertAction(title: "Google Maps", style: .Default, handler: { (action: UIAlertAction!) -> Void in
if (UIApplication.sharedApplication().canOpenURL(NSURL(string:"comgooglemaps://")!)) {
UIApplication.sharedApplication().openURL(NSURL(string:
"comgooglemaps://?daddr=\(self.mapView!.selectedMarker.position.latitude),\(self.mapView!.selectedMarker.position.longitude)")!)
} else {
UIApplication.sharedApplication().openURL(NSURL(string:
"http://maps.google.com/maps?daddr=\(self.mapView!.selectedMarker.position.latitude),\(self.mapView!.selectedMarker.position.longitude)")!)
}
}))
openMapsActionSheet.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
presentViewController(openMapsActionSheet, animated: true, completion: nil)
}
// 1
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
// 2
if status == .AuthorizedWhenInUse {
// 3
locationManager.startUpdatingLocation()
//4
mapView.myLocationEnabled = true
mapView.settings.myLocationButton = true
}
}
// 5
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
if let location = locations.first as? CLLocation {
// 6
mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 6, bearing: 1, viewingAngle: 1)
// 7
locationManager.stopUpdatingLocation()
}
}
}
In absence of the complete code, here is what i can extrapolate:
I am assuming you have a mapView that is already set.
I am assuming mapView!.selectedMarker gets populated only when the user selects the pin, else it is nil (or some other value u choose) then,
Now, directionTapped should be:
if self.mapView!.selectedMarker != nil {
<Your current Code>
} else {
<Code to Show the new alert about pin not selected>
}
with this code it worked from me:
func directionTapped(){
//code input from Apple-and-Oranges
if self.mapView!.selectedMarker != nil {
//current code
let openMapsActionSheet = UIAlertController(title: "Open in Maps", message: "Choose a maps application", preferredStyle: .ActionSheet)
openMapsActionSheet.addAction(UIAlertAction(title: "Apple Maps", style: .Default, handler: { (action: UIAlertAction!) -> Void in
let placemark = MKPlacemark(coordinate: CLLocationCoordinate2DMake(self.mapView!.selectedMarker.position.latitude, self.mapView!.selectedMarker.position.longitude), addressDictionary: nil)
let item = MKMapItem(placemark: placemark)
let options = [MKLaunchOptionsDirectionsModeKey:
MKLaunchOptionsDirectionsModeDriving,
MKLaunchOptionsShowsTrafficKey: true]
item.openInMapsWithLaunchOptions(options as [NSObject : AnyObject])
}))
openMapsActionSheet.addAction(UIAlertAction(title: "Google Maps", style: .Default, handler: { (action: UIAlertAction!) -> Void in
if (UIApplication.sharedApplication().canOpenURL(NSURL(string:"comgooglemaps://")!)) {
UIApplication.sharedApplication().openURL(NSURL(string:
"comgooglemaps://?daddr=\(self.mapView!.selectedMarker.position.latitude),\(self.mapView!.selectedMarker.position.longitude)")!)
} else {
UIApplication.sharedApplication().openURL(NSURL(string:
"http://maps.google.com/maps?daddr=\(self.mapView!.selectedMarker.position.latitude),\(self.mapView!.selectedMarker.position.longitude)")!)
}
}))
openMapsActionSheet.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
presentViewController(openMapsActionSheet, animated: true, completion: nil)
}
//Added a alert message
else {
let alertController = UIAlertController(title: "Choose Pin!", message: "\nChoose Pin to get navigation from current location", preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: { (action: UIAlertAction!) in
}))
presentViewController(alertController, animated: true, completion: nil)
}
}