Custom marker InfoWindow in google maps iOS swift? - swift

I'm using google map iOS in my app , i want to show custom marker info window.How can i create it?
I'm using storyboards and swift as the language.

I had one such problem with my app.
In your ViewController.swift:
class ViewController: GMSMapViewDelegate {
func mapView(_ mapView: GMSMapView, markerInfoContents marker: GMSMarker) -> UIView? {
let placeMarker = marker as! PlaceMarker
if let infoView = UIView.viewFromNibName("MarkerInfoView") as? MarkerInfoView {
infoView.nameLabel.text = placeMarker.place.name
if let photo = placeMarker.place.photo {
infoView.placePhoto.image = photo
} else {
infoView.placePhoto.image = UIImage(named: "generic")
}
return infoView
} else {
return nil
}
}
}
2.Then create a UIView class:
import UIKit
class MarkerInfoView: UIView {
#IBOutlet weak var placePhoto: UIImageView!
#IBOutlet weak var nameLabel: UILabel!
}
Then create a xib file named the same as UIView class:
Note that the class name is the same as UIView class. You can add label and images as per your requirement. Connect those IBOutlets to the UIView class as shown.
Hope this helps you. All the Best!

Define a delegate for your GMSMapView and implement this function in your delegate:
func mapView(_ mapView: GMSMapView, markerInfoWindow marker: GMSMarker) -> UIView? {
}
You can create the view programmatically inside this function, or through a nib file.
UPDATE
Do not forget to change the marker's infoWindowAnchor:
https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_marker.html#a6668957ca7b6857355ee6cd9ab944a92

Related

Exception in Delegate CustomClass UIView

I am trying to delegate a function with which I will call the new ViewController. In run, it gets this error:
setValue: forUndefinedKey:]: this class is not key value coding-compliant for the key mapView. '
What am I doing wrong or how can I fix it? I will be grateful for all the tips.
import UIKit
import MapKit
ViewController.swift:
class ViewController: UIViewController, CustomViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName:"Maps", bundle:nil)
let MapsView = nib.instantiate(withOwner: self, options: nil).first as! Maps
MapsView.delegate = self
}
func showWaypointDetails() {
print("show")
}
Maps.swift:
protocol CustomViewDelegate: class {
func showWaypointDetails()
}
class GpsMaps: UIView, MKMapViewDelegate {
#IBOutlet var view: UIView!
#IBOutlet weak var mapView: MKMapView!
weak var delegate: CustomViewDelegate?
}
It looks like you are either not instantiating the right view or the view is not set up correctly.
In your Maps.xib file:
Check if the "File's Owner" points to your Maps.swift class
Check if you have a MKMapView outlet named "mapView"
You are casting the nib (which I assume contains a MKMapView) as Maps, which is just a simple protocol. In doing this you will lose all mapView functionality as the app won't know it's a MapView.
You need to load it and cast it as the MapView Class you are using, and then adopt the protocol in your MapView class...
override func viewDidLoad() {
super.viewDidLoad()
let nib = UINib(nibName:"Maps", bundle:nil)
let mapsView = nib.instantiate(withOwner: self, options: nil).first as! MyMapViewClass
mapsView.delegate = self
}
extension MyMapViewClass: Maps {
// implement showWaypointDetails() or implement it as a default in a protocol extenstion
}

MKPinAnnotationView doesn't show in MKMapView even though it's properly added using Swift

I'm developing an OSX app.
I've subclassed a MKAnnotation:
import Foundation
import MapKit
class LocationAnnotation: NSObject, MKAnnotation {
var image: NSImage?
var title: String?
var coordinate: CLLocationCoordinate2D
init(image anImage: NSImage?, title aTitle: String, coordinate aCoordinate: CLLocationCoordinate2D) {
self.image = anImage
self.title = aTitle
self.coordinate = aCoordinate
}
}
In my NSViewController subclass, I've added a MKMapViewDelegate and in Interface Builder I've added a MKMapView and set its delegate to NSViewController.
To find out what's wrong, I'm adding three locations in my ViewDidLoad method, into an array. I'm adding those annotations to my map in ViewDidAppear. I plan to move that to a background thread when I figure out what's wrong.
import Cocoa
import MapKit
class ShowLocationsViewController: NSViewController, MKMapViewDelegate {
#IBOutlet var locationMap: MKMapView!
private var myLocationArray: [LocationAnnotation] = []
private var myRegion: MKCoordinateRegion!
//#MARK: - UIViewController
override func viewDidLoad() {
super.viewDidLoad()
myLocationArray = []
myRegion = nil
let locLondon = LocationAnnotation(image: nil, title: "London", coordinate: CLLocationCoordinate2DMake(51.522617, -0.139371))
let locWembley = LocationAnnotation(image: nil, title: "Wembley", coordinate: CLLocationCoordinate2DMake(51.555909, -0.279600))
let locGreenwich = LocationAnnotation(image: nil, title: "Greenwich", coordinate: CLLocationCoordinate2DMake(51.476572, -0.001596))
myLocationArray.append(locLondon)
myLocationArray.append(locWembley)
myLocationArray.append(locGreenwich)
myRegion = MKCoordinateRegion.init(center: locLondon.coordinate, span: MKCoordinateSpanMake(0.20, 0.20)) // 20km span
}
override func viewDidAppear() {
locationMap.addAnnotations(myLocationArray)
locationMap.setRegion(myRegion, animated: true)
}
}
When using delegate's method viewFor annotation: I print out the title of each annotation in a log and all three of them are listed. In another delegate's method didAdd I'm printing out the number of annotations of my map in a log and it prints out three. But on my map, there are no annotations displayed. I tried panning and zooming with no success. Region gets properly set and displayed though.
//#MARK: - MKMapViewDelegate
func mapView(_ mapView: MKMapView, didAdd views: [MKAnnotationView]) {
print(locationMap.annotations.count, views.count)
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is LocationAnnotation {
let annotationIdentifier = "Location"
var annotationView = locationMap.dequeueReusableAnnotationView(withIdentifier: annotationIdentifier) as! MKPinAnnotationView?
if annotationView == nil {
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotationIdentifier)
}
annotationView!.canShowCallout = true
print(annotationView!.annotation!.title ?? "no view")
return annotationView
} else {
print("no annotation")
return nil
}
}
When I try the same code in an iOS app, everything works. I assume there is nothing wrong with my delegate because methods are properly called.
I would appreciate any help you can give me.
I figured out the problem, the way the window is being called.
I created a variable mainWindowController in my AppDelegate, then I subclassed my main NSViewController so that I could hook up AppDelegate to it.
let appDelegate = NSApp.delegate as! AppDelegate
appDelegate.mainWindowController = self
Afterwards I used this code to call my window which was errornous:
let mapViewController = mainWindowController?.storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier.init(rawValue: "ShowLocationsID")) as! ShowLocationsViewController
mainWindowController?.contentViewController?.presentViewControllerAsModalWindow(mapViewController)
I changed that in a way that I created a segue in my storyboard and called the following code which worked and my pins did show:
performSegue(withIdentifier: NSStoryboardSegue.Identifier(rawValue: "ShowLocations"), sender: self)

How would I go about adding a uiview vertically above a uiview within an inputAccessoryView?

I'm trying to add a uiview containing multiple buttons, above my current input accessory view. My current input accessory view is a growing textField (like iOS standard Text Message app).
class ViewController: UIViewController {
let textInputBar = ALTextInputBar()
// The magic sauce
// This is how we attach the input bar to the keyboard
override var inputAccessoryView: UIView? {
get {
return textInputBar
}
}
// Another ingredient in the magic sauce
override func canBecomeFirstResponder() -> Bool {
return true
}
}
Example of what I'm trying to do, the app (Facebook Messenger) has a growing textfield or textinput, and in this case, an bar of buttons bellow.
My current view, as mentioned earlier.
try this code
class ViewController: UIViewController {
#IBOutlet weak var myTextField: UITextField!
var textInputBar:UIView = ALTextInputBar()// if it is a uiview type
override func viewDidLoad() {
super.viewDidLoad()
myTextField.inputAccessoryView = textInputBar
}
}

How to add a UIView which is created in storyboard as a pop-up in Swift?

I did the following:
1. Dragged UIView to place it in the ViewController ribbon
Created a custom UIView class and added the outlets to the 'Edit Profile View' view fields:
import UIKit
class EditProfileView: UIView {
let globalDataHandler = GlobalDataHandler.sharedInstance
#IBOutlet weak var firstNameTextField: UITextField!
#IBOutlet weak var lastNameTextField: UITextField!
#IBOutlet weak var userNameTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
#IBAction func saveEditButton(sender: AnyObject) {
}
#IBAction func cancelEditButton(sender: AnyObject) {
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
}
Gave 'EditProfileView' class as the Custom Class for the 'Edit Profile View' view in Storyboard.
Created an object for 'EditProfileView' class in ProfileViewController and added the 'Edit Profile View' view to the main view upon clicking edit button in ProfileViewController.
class ProfileViewController: UIViewController {
let profileView = EditProfileView()
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func editProfileButton(sender: AnyObject) {
profileView.firstNameTextField.text = "First Name"
profileView.lastNameTextField.text = "Last Name"
profileView.userNameTextField.text = "User Name"
profileView.emailTextField.text = "Email"
let testFrame : CGRect = CGRectMake(50,100,300,300)
profileView.frame = testFrame
self.view.addSubview(profileView)
}
}
But, the 'Edit Profile View' view doesn't appear on ProfileViewController.
Please help.
You have to link your UIView and your View (should be a distinct UIViewController) in the Xib.
profileView = storyboard.instantiateViewControllerWithIdentifier("ProfileViewController")
You must have an UIPresentationController for your ProfileVC
class ProfilePresentationController : UIPresentationController {
override func frameOfPresentedViewInContainerView() -> CGRect {
return CGRect(x: (presentingViewController.view.frame.width / 2.0) - 150.0, y: (presentingViewController.view.frame.height / 2.0) - 100.0, width: 300.0, height: 200.0)
}
}
Your EditProfileView must implement the following delegate:
UIViewControllerTransitioningDelegate
the following properties of your profileView must also be set to:
profileView.modalPresentationStyle = UIModalPresentationStyle.Custom
profileView.transitioningDelegate = self
After that you can implement the delegate required method
func presentationControllerForPresentedViewController(presented: UIViewController, presentingViewController presenting: UIViewController, sourceViewController source: UIViewController) -> UIPresentationController? {
return ProfilePresentationController(presentedViewController: presented, presentingViewController: presenting)
}

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
}