Google Maps Showing speechbubble in marker info window iOS - ios

I am using GoogleMaps SDK in my iOS application. I have implemented custom info window for GoogleMaps and calling it my ViewController as,
func mapView(mapView: GMSMapView!, markerInfoContents marker: GMSMarker!) -> UIView! {
var calloutView:CalloutView = NSBundle.mainBundle().loadNibNamed("CalloutView", owner: self, options: nil)[0] as! CalloutView
views!.detailDisclosure.addTarget(self, action: "detailDisclosureButton_Clicked:", forControlEvents: UIControlEvents.TouchUpInside)
views.labelText.text = "ABC Text"
return views
}
And getting output as below
Info window overlapping and showing bottom edges as below. Also button on info window not getting clicked. Please help for the same.

With my experience, - mapView:markerInfoContents: have some problems. In my case, I ended up using - mapView:markerInfoWindow: instead. In this case, you have to draw balloon image by yourself, like this:
Also button on info window not getting clicked.
As documented on the bottom of this, markerInfoWindow is rendered as an image, but not true UIView.
Note: The info window is rendered as an image each time it is displayed on the map. This means that any changes to its properties while it is active will not be immediately visible. The contents of the info window will be refreshed the next time that it is displayed.
It does not receive any UI events. So, sad to say, any UIControls on markerInfoWindow is useless. The only supported way is to use - mapView:didTapInfoWindowOfMarker: delegate method, that means, you can not define multiple clickable areas on the info window.

Related

Disable DoubleTapGesture Zoom out on MKMapView

I have observed MKMapView zoom-out on Double tap gesture, I didn't find any way to disable it. I tried to add own Double Tap Gesture to catch Double tap action but it still zoom out. Any thought?
There is no API to disable or change double-tap behavior with MKMapView.
But, if you really want to do so, one approach would be to find and remove the double-tap gesture recognizer from the MKMapView object.
In the project you shared, you could do that in makeUIView in your UIMapView class:
func makeUIView(context: UIViewRepresentableContext<UIMapView>) -> UIViewType {
self.configureView(mapView, context: context)
setRegion(to: palce)
if let v = mapView.subviews.first,
let ga1 = v.gestureRecognizers
{
let ga2: [UITapGestureRecognizer] = ga1.compactMap { $0 as? UITapGestureRecognizer } .filter { ($0.numberOfTapsRequired == 2) }
for g in ga2 {
v.removeGestureRecognizer(g)
}
}
return mapView
}
I wouldn't necessarily suggest that you do so, however.
Apple may change the MKMapView object in the future, which could then break this.
User's tend to prefer that common UI elements behave in expected ways.
Personally, I get rather annoyed when using an app and the developer has changed standard functionality of UI elements. For example, if I see a table view row with a disclosure indicator (the right-arrow / chevron), I expect that tapping the row will "push" to another screen related to that row. I've seen apps that do not follow that pattern, and it just gets confusing.

iOS: Creating dynamic speech balloons for annotations that appear from user input using MapBox

In the code posted, when you click on the annotation, the speech balloon pops up to say
Hello World!
Welcome to my marker
I would like to know how to make the speech bubble appear while using the app, and have the speech bubble display some text that the user would enter in, and disappear after about an hour or so. The bubble would be able to be seen by other users even if the user logged out or closed the app, and the bubble would still be open when the user goes back into the app, unless the window of time for the bubble has passed.
Thank-you
import Mapbox
class ViewController: UIViewController, MGLMapViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let mapView = MGLMapView(frame: view.bounds)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Set the map’s center coordinate and zoom level.
mapView.setCenter(CLLocationCoordinate2D(latitude: 40.7326808, longitude: -73.9843407), zoomLevel: 12, 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"
// Add marker `hello` to the map.
mapView.addAnnotation(hello)
}
// Use the default marker. See also: our view annotation or custom marker examples.
func mapView(_ mapView: MGLMapView, viewFor annotation: MGLAnnotation) -> MGLAnnotationView? {
return nil
}
// Allow callout view to appear when an annotation is tapped.
func mapView(_ mapView: MGLMapView, annotationCanShowCallout annotation: MGLAnnotation) -> Bool {
return true
}
}
Are you wanting the user to enter text into a text field inside the annotation bubble? If so, consider subclassing MGLPointAnnotation and adding a text field to it. That might be a bit tricky though since it would appear that MGLPointAnnotation is a subclass of MGLShape, which appears to not be a subclass of the usual UIKit hierarchy of view/view-controller classes. You may be better off swapping out the Mapbox framework for a basic MapKit solution (...I don't know for what else you are relying on Mapbox though).
Apple's MapKit does have MKAnnotationView. There is a definite answer for how to add a UITextField to MKAnnotationView. See how to add UITextField in MKAnnotationView Title. You may need to modify the answer depending on how you want your annotation to behave.
If, on the other hand, you were thinking of the user entering text into a text field through another screen in the iOS app, there are many easy ways to properly implement a UITextField in a UIViewController, UIView, UITableViewController, UICollectionView, etc.
Alternatively, if you were thinking about the user entering text through a website, that is trivially easy with HTML forms.
For the approximate 1 or 3 hour(s) timeframe for displaying the bubble before it goes away, you would need to add a createdTimestamp property to the MKAnnotationView subclass. Just compare the current time periodically to the createdTimestamp on the annotation and if currentTime >= annotation.createTimestamp + oneHour, remove the annotation from the map. You can see about dates in Swift here: https://developer.apple.com/documentation/foundation/date
As far as "other users" seeing the bubble goes, that would require some sort of networked solution (such as a central server that synchronizes with these bubbles' data and then broadcasts them to other users). You would need a networked setup anyway if you were thinking of using website(s) to gather/display map data.
Presumably from your other question, I assume that you are using the map fullscreen. There are several approaches to this.
You could use the default I accessory button to add a target action to it. Which calls a custom UIView which has a textView and a submit button. Which then modifies your annotation.
Or you could modify your mapview to show a small textbox at the bottom of the screen which is then shifted upwards whilst editing and added to your annotation upon submitting.
When it comes to your timeout question I did not find anything in the MapBox's documentation to get you the results you want. I believe it needs some sort of backend server side timer function which will handle this accordingly.

Reloading Google Map View when adding and removing markers

We are coding in Swift to create an application with UI buttons. These UI buttons will add or remove markers depending on its status. Because we want the buttons to be layered on top of google maps we have two view controllers. The top view controller contains a button. When the button is pressed, we want to remove the markers that have a "bad" status.
This is our code to remove the marker:
func showOnlyGood(){
mapView.clear() //this is the google map (GMSMapView.map)
for x in arrayOfGood { //Array of good markers
x.map = mapView //Set good markers to show
}
for y in arrayOfBad { //Array of bad markers
y.map = nil //removes markers from map
}
}
The google maps gets updated if the function call is in viewDidLoad(), but when we call the function in the top view controller with the buttons it does not update the map accordingly.
We think this is an issue with refreshing the google map view and have tried many different solutions, but the google map view only shows what is initially in viewDidLoad().
First, if you just want the buttons to be layered on top of the map, just add the buttons to the view after you've added the map to the view; do not create a second view controller. Your problem is most likely caused by this awkward setup. You also don't have an #objc prefix in your action method, which would definitely prevent the button from executing its action.
#objc func updateButtons() {
mapView.clear() // clear the map
for i in someArray {
let marker = GMSMarker()
// configure parameters
marker.map = mapView
}
}
That method will update your map's markers. There is [probably] never a need to refresh the map, even if you want to change styles.

swift google maps open modal on marker tap

Within my swift app I used to open up a infowindow when a map marker was tapped. I am in the process of changing this instead to open up a viewcontroller as a modal and present the information in it instead. The problem I'm encountering is that the modal doesn't present from when a map marker is tapped. The map marker gets called, the data I need is passed to the controller but the controller itself won't appear. It looks to exist as when I tap the marker a second time, it'll error out about the activity already presenting.
Here is the code on tapping the marker
func mapView(_ mapView: GMSMapView, didTap marker: GMSMarker) -> Bool {
mapView.animate(toLocation: CLLocationCoordinate2D(latitude: marker.position.latitude, longitude: marker.position.longitude))
detailsViewController.marker = marker
present(detailsViewController, animated: true)
return true
}
The viewcontroller does present correctly if not done with a map marker. If I tap a button and call the present, it show as it should.
Anyone do something like this, have an idea of what needs to be changed, or have some code they can share?
Update: it mysteriously started working so the code is correct. No change. Just rebuilt a few times. Even clean didn't resolve it but building it numerous times did.

iOS app freezes when loading custom info window for marker on Google Maps

I am trying to implement a custom info window on my Google Maps Marker on an iOS app. (As is done here and here for example.)
I have created a xib and a UIView class for it. It is called CustomInfoWindow.xib and the class is CustomInfoWindow.swift.
My Custom Info Window is currently blank, i.e. I have not yet added any UIControls to my xib. I have also not yet added any code to my class file.
The CustomInfoWindow.swift file basically looks like:
import UIKit
class CustomInfoWindow: UIView {}
In my ViewController for my maps my markerInfoWindow method is as follows:
func mapView(mapView: GMSMapView!, markerInfoWindow marker: GMSMarker!) -> UIView! {
let customInfoWindow = NSBundle.mainBundle().loadNibNamed("CustomInfoWindow", owner: self, options: nil)[0] as! CustomInfoWindow
return customInfoWindow
}
When I run the code and I click on one of my markers, the blank CustomInfoWindow displays fine.
The strange thing is that the moment I add any UI Element to the CustomInfoWindow.xib in the Interface Builder and run my app again then suddenly when I click on a marker the app freezes. (For example when I add a UILabel or a UIImage to the CustomInfoWindow.xib.) If I remove the UI Element then the blank nib displays fine over the marker.
If I test my nib by adding it as a subview on some View Controller then it loads fine with my UILabel and UIImage. However, when I use that same nib in the markerInfoWindow the app freezes.
What can the problem be?
UPDATE:
This issue occurred on version 1.13 of the Google Maps SDK for iOS and it turned out to be a bug on that version.
I have the same issue. It's a GoogleMaps's bug!
Freezing apperrs in version 1.13.0.
You can use:
pod 'GoogleMaps', '1.12.3'
Found the proper workaround for 1.13
Add the following code to the subclass CustomInfoWindow
override func didMoveToSuperview() {
superview?.autoresizesSubviews = false;
}
Source: https://code.google.com/p/gmaps-api-issues/issues/detail?id=9525

Resources