Show custom location with pin on Map with MapKit (Swift) - swift

I am trying to create a view for in my app which shows the location of a restaurant. When the user enters the view, it shows something like this
But instead shows the location of the restaurant with a pin and a more zoomed in view. I am new to MapKit and have not been able to make any progress.
This is what my view consists of.
And this is what my view controller consists of.
import UIKit
import MapKit
class FD1ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
private let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

import UIKit
import MapKit
class FD1ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
//Create the pin location of your restaurant(you need the GPS coordinates for this)
let restaurantLocation = CLLocationCoordinate2D(latitude: 111.0, longitude: 111.0)
//Center the map on the place location
mapView.setCenter(restaurantLocation, animated: true)
}
}
This should do it. I hope it helps!

Related

Take screenshot of ARKit view

How would I insert a button and use it to take a photo and place it in photo library. I have noticed when using arkit I cant drag buttons and place them over the view. I am seen some people online say you use snapshot() for taking the photo.
import UIKit
import SceneKit
import ARKit
class ViewController: UIViewController, ARSCNViewDelegate {
#IBOutlet var sceneView: ARSCNView!
override func viewDidLoad() {
super.viewDidLoad()
// Set the view's delegate
sceneView.delegate = self
// Show statistics such as fps and timing information
sceneView.showsStatistics = true
// Create a new scene
let scene = SCNScene(named: "art.scnassets/ship.scn")!
// Set the scene to the view
sceneView.scene = scene
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
// Run the view's session
sceneView.session.run(configuration)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Pause the view's session
sceneView.session.pause()
}
func session(_ session: ARSession, didFailWithError error: Error) {
// Present an error message to the user
}
func sessionWasInterrupted(_ session: ARSession) {
// Inform the user that the session has been interrupted, for example, by presenting an overlay
}
func sessionInterruptionEnded(_ session: ARSession) {
// Reset tracking and/or remove existing anchors if consistent tracking is required
}
}
I made a simple demo to show you how to combine snapshot(), ARSCNView and UIBUtton. So you may define your storyboard in this way:
as you can see, the button is inside the main view but outside and above the ARKit view
then your ViewController might be something like:
import UIKit
import ARKit
class ViewController: UIViewController {
#IBOutlet var arkitView:ARSCNView!
#IBOutlet var outputImageView:UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
arkitView.session.run(ARWorldTrackingConfiguration())
}
#IBAction func takeScreenshotAction() {
outputImageView.image = arkitView.snapshot()
}
}
final result is:

Swift MKMapViewDelegate - Transferring coordinates between view controllers

I am trying to construct a Map App that can receive user inputs of latitude and longitude coordinates that when entered, will place a pin on a map in a different tab. My FirstVC consists of a button "Add Locations" that segues to OtherVC which the user can input the coordinates. SecondVC consists of the MapView. My initial idea is to have a specific array of coordinates, and any new coordinates will be appended to this array. The execution is where I am lacking, because I am not sure how to transfer this array to the MapView. Here is what I have so far:
For the input of coordinates:
import UIKit
import CoreLocation
class OtherVC: UIViewController {
#IBOutlet weak var latitudeField: UITextField!
#IBOutlet weak var longitudeField: UITextField!
var coordinates = [CLLocationCoordinate2D]()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func addToMap(_ sender: Any) {
let lat = Double(latitudeField.text!)
let long = Double(longitudeField.text!)
self.coordinates.append(CLLocationCoordinate2D(latitude: lat!, longitude: long!))
}
}
For the MapView:
import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
var coordinates = [CLLocationCoordinate2D]() {
didSet {
// Update the pins
// Since it doesn't check for which coordinates are new, it you go back to
// the first view controller and add more coordinates, the old coordinates
// will get a duplicate set of pins
for (index, coordinate) in self.coordinates.enumerated() {
let annotation = MKPointAnnotation()
annotation.coordinate = coordinate
annotation.title = "Location \(index)"
mapView.addAnnotation(annotation)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
let identifier = "pinAnnotation"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.canShowCallout = true
}
annotationView?.annotation = annotation
return annotationView
}
}
I think you need is get your second ViewController MapViewController from your tabBarController and then pass the coordinates array, so in your addToMap Action replace with this
#IBAction func addToMap(_ sender: Any) {
let lat = Double(latitudeField.text!)
let long = Double(longitudeField.text!)
self.coordinates.append(CLLocationCoordinate2D(latitude: lat!, longitude: long!))
//here we pass the coordinate array to mapViewController
if let mapViewController = self.tabBarController?.viewControllers?[1] as? MapViewController
{
mapViewController.coordinates = self.coordinates
}
}
You need also add a navigation controller, like in the picture
I hope this helps you
Generally speaking I only use the method of directly passing the data from one ViewController to the next if there is a parent child relationship and I can do it in prepareForSegue or in and unwind (child to parent). Otherwise I think its better to use the publisher subscriber model with Notification. When your coordinate changes you post a Notification:
NotificationCenter.default.post(name: NSNotification.Name("MapViewController.coordinate.updated"), object: self, userInfo: nil)
Now anyone who cares about MapViewController's coordinates changing can listen:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(coordinateUpdated), name: NSNotification.Name("coordinate.updated"), object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
#objc private func coordinateUpdated( notification: Notification) {
if let source = notification.object as? MapViewController {
print(source.coordinates)
}
}
This makes the views loosely coupled and MapViewController doesn't need to care about who needs to be updated; the subscribers are responsible for registering themselves.

I can't add current location to Google Maps

import UIKit
import GoogleMaps
import CoreLocation
class ViewController: UIViewController {
let locationManager = CLLocationManager()
var mapView: GMSMapView?
override func viewDidLoad() {
super.viewDidLoad()
GMSServices.provideAPIKey("XYZ")
let camera = GMSCameraPosition.cameraWithLatitude(37.621262,longitude: -122.378945, zoom: 12)
mapView = GMSMapView.mapWithFrame(CGRectZero, camera: camera)
view = mapView
}
}
What should I add to this code?
This should help you,Please check.
import UIKit
import GoogleMaps
import CoreLocation
class ViewController: UIViewController {
let locationManager = CLLocationManager()
var mapView: GMSMapView?
override func viewDidLoad()
{
super.viewDidLoad()
GMSServices.provideAPIKey("XYZ")
let camera = GMSCameraPosition.camera(withLatitude: 37.621262,longitude: -122.378945, zoom: 12)
mapView = GMSMapView.map(withFrame: CGRect.init(), camera: camera)
// Below line is to default show user current location(Bue dot with circular accuracy radius around it)
mapView!.isMyLocationEnabled = true
view = mapView
}
}
Hope that helps.

assign GMSMapView to UIView in Swift

I have created these two variables
var googleMap = GMSMapView()
#IBOutlet weak var mapView: UIView!
I'm assigning googleMap to mapView in viewDidLoad()
override func viewDidLoad() {
super.viewDidLoad()
self.mapView = self.googleMap //Throwing error as 'Google Maps SDK for iOS must be initialized via [GMSServices provideAPIKey:...] prior to use'
}
I'm providing key in AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
GMSServices.provideAPIKey("AIzaSyB6aQxEmza-wUpOPU60aREWReRIAEAvrHs")
return true
}
Can anyone point me in the direction to solve this?
You do not assign the GMSMapView to your UIView in that way. Here's how you do it
Change the class of your UIView to GMSMapView
first you should change the class of UIView to the GMSMapView from story board , then you should make a IBOutlet from that view in view controller and set camera and else like this
#IBOutlet weak var mapView: GMSMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.camera = camera
}

Cancel button only clears the recipient number and does not return back to app?

The cancel button only clears the recipient phone number but does not go back to the app? Any help? Here is the code I'm currently using.....
import UIKit
import MessageUI
class ViewController: UIViewController, MFMessageComposeViewControllerDelegate {
#IBOutlet weak var txtMsg: UITextField!
#IBOutlet weak var txtPhone: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func sndSMS(sender: AnyObject) {
txtMsg.resignFirstResponder()
txtPhone.resignFirstResponder()
let msgVC = MFMessageComposeViewController()
msgVC.body = txtMsg.text!
msgVC.recipients = ["1-206-724-8288"]
msgVC.messageComposeDelegate = self;
self.presentViewController(msgVC, animated: true, completion: nil)
You're assigning the delegate but you are not implementing the method listed here:
https://developer.apple.com/documentation/messageui/mfmessagecomposeviewcontrollerdelegate/1614061-messagecomposeviewcontroller
func messageComposeViewController(_ controller: MFMessageComposeViewController,
didFinishWithResult result: MessageComposeResult)