Programmatically display a GMSMarker's info window - swift

I know there is already a question similar to this on SO (Displaying info window when tapped marker in google maps iOS sdk while implementing mapView:didTapMarker: delegate method implemented) but the answer does not apply in my case.
In my mapView(didTap:) delegate method, it has to return true because I programmatically determine the camera position when a marker is tapped. If I return true like the answer in the above question says, the map is automatically centered on the selected marker, which I do not want. Since I return true, tapping a marker does not display the marker's information window, which I still want to occur, so is there a way for me to do that programmatically?
I don't think the code in my mapView(didTap:) delegate method is necessary for answering this question, but if anyone needs it, let me know. (Keep in mind that my question question refers to the delegate method for when a marker is tapped, not the delegate method for when an info window is tapped, mapView(didTapInfoWindowOf:))
Thanks in advance.
Edit:
Looking through the Google Maps Documentation, I found out that there is a method for what I am looking for in JavaScript called showInfoWindow() that you call on the marker who's info window you want to show (this is the link to the documentation I'm talking about). So does anyone know a Swift 3 alternative to this method?
Edit:
If I return false in the delegate method, the camera instantly moves to the marker's location for a split second, and then pans over to the location I programmatically tell it to move to. This technically works, but it is ugly and not fluent, so I still need a way to programmatically show the marker's information window while the delegate method returns true.

After going on google's issue tracker and submitting a post, I found out that mapView.selectedMarker() = marker does not actually have any connection to the mapView(didTap:) delegate method, so returning true in the delegate method has no impact on the selectedMarker() method's functionality.
As a result I can just add mapView.selectedMarker() = marker in the delegate method after customizing the location I want to animate the mapView to and before returning true, which causes the marker's info window to pop up without messing with the camera position.

Related

What is the imagePickerController delegate method before the didfinishpickingmediawithinfo method is called?

So I have a visual cue (PNG rectangle lines) that pops up when taking a picture for this test app I’m doing.
So I remove the visual cue in the did finish picking media delegate method and/or the didcancel method as well. But I can’t find info on a delegate method for inbetween. Is there one? If there isn’t, is there a way to handle using a visual cue during image taking but not during the deciding “phase”?
I've looked at the Apple Docs but can't find anything so far. I'm trying to be better as far as attention to detail but I still struggle so my apologies if I didn't see it
I don't think there's code necessary to show so I can't show sample code.
No, the only delegate methods are imagePickerController(_:didFinishPickingMediaWithInfo:) and imagePickerControllerDidCancel(_:).
If you want to customize the user interface during picture taking, you can take a few approaches.
First, use the cameraOverlayView property to customize the UI.
Second, note that the UIImagePickerController is itself a UINavigationController. You can therefore set its delegate and respond to navigationController(_:willShow:animated:) to be notified when the user is about to move between view controllers. You could implement logic here to show, hide, or otherwise adjust your custom UI.

Xcode 4.5 Storyboard 'Exit'

I have just installed Xcode 4.5 for iOS6 support, and I have seen a new icon called 'Exit' in my Storyboard, listed under my view controllers along with 'First Responder' etc. A little green icon labeled 'Exit'.
I can find anything about it, nor work out how it can be used. How does it work?
This is called an "Unwind Segue". Unfortunately there's no documentation for this so far except a brief mention on XCode 4.5 new features list that states:
Unwind segues can allow transitioning to existing instances of scenes
in a storyboard
The good news is that there is a session from WWDC 2012 explaining those creatures (among other things).
You can just login to Apple's iOS Dev Center with your developer account details and then go to the WWDC 2012 videos page and watch "Adopting Storyboard in your App" (it's fifth from the top) The discussion of unwind segues starts at time 37:20.
Update:
Here is some more info on the subject from Apple's documentation
A placeholder object named Exit for unwinding seques. By default, when
a user dismisses a child scene, the view controller for that scene
unwinds (or returns) to the parent scene—that is the scene that
originally transitioned to the child scene. However, the Exit object
enables a view controller to unwind to an arbitrary scene.
(From iOS6 docset > General > Getting Started)
And here is a nice example of how you can implement one
Another Update:
Here is a technical note from Apple regarding this topic.
Imagine you have a sequence of views in your storyboard:
A -> ... -> Z
You want to have a button on view Z which allows the user to go all the way back to A.
So what you need to do is give the view that you want to back all the way out to, in this case, A, an instance method which is marked as a IBAction and takes in a single parameter of type UIStoryboardSegue *. The name of the method and variable don't matter. What you do within the implementation doesn't matter, either. Here's an example:
Obj-C:
In A's Interface (not Z's):
- (IBAction)cancelSignup:(UIStoryboardSegue *)unwindSegue;
In A's Implementation (not Z's):
- (IBAction)cancelSignup:(UIStoryboardSegue *)unwindSegue {
// Only "implemented" to satisfy a respondsToSelector: search.
// You can actually implement more stuff here, if you want, IE, if
// you need to reach out to a server to mention that this screen was
// returned to from a later screen.
}
Swift:
In A's source (not Z's):
#IBAction func cancelSignup(unwindSegue: UIStoryboardSegue) {
// Only "implemented" to satisfy a respondsToSelector: search.
// You can actually implement more stuff here, if you want, IE, if
// you need to reach out to a server to mention that this screen was
// returned to from a later screen.
}
Now, within your storyboard, control drag from an element on Z (IE, a cancel button) to Z's Exit. It'll scan through all of the views higher up in the view hierarchy which have an IBAction that accepts only a single UIStoryboardSegue * as an action and list them for you to pick from.
Hopefully this was more straight forward and helpful than the existing answers. I found that this link was particularly useful, so if there's a detail you're still fuzzy on after reading my answer, maybe this can help you (I tried to just condense all the useful info from this long article into a short answer):
http://www.freelancemadscience.com/fmslabs_blog/2012/9/24/advanced-storyboard-techniques.html
See also Cannot Connect Storyboard Unwind Segue which clarifies the requirements to bring the Exit icon to life. You must have, higher up in the view controller hierarchy, a method that is:
Marked as IBAction
Takes one parameter that is a UIStoryboardSegue*
If both those conditions are met, the Exit icon will see it and will permit you connect through to it by control-dragging from a button in the same view controller.
I have also now posted the world's simplest example here:
https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/ch19p638presentedViewControllerStoryboard (fixed 12 July 2013)
This shows how trivially easy it now is to segue to and back from a presented view controller, as opposed to all the work you had to do previously in order to hand info back and forth (the stuff in the template with a delegate and a protocol, all of which can now be deleted).
Just adding a slight subtlety to the requirements definition that might help. This is based on experimenting in Xcode 4.6. I found that it is specifically and only the declaring(!) of the method that enables the desired control-drag response from Xcode. Here's what I found to be the full requirements:
Marked as IBAction
Takes one parameter that is a UIStoryboardSegue*
You must have an action declared (but not necessarily implemented [meaning a method in the .M implementation section]).
It can be in any class's interface declaration, even the interface section of a .M, except the appdelegate class. (I did not see any dependency on its position in the controller hierarchy. You can add any old file and the system seems to aggregate all the methods that have the UIStoryboardSegue parameter and display them on the Exit icon's menu.) Note that the control-drag menu will even show you your method if the method is in the class of the scene you are manipulating in the storyboard editor, but it will appear without a colon and does not seem to trigger any action at runtime.
Example:
-(IBAction)anymethodname:(UIStoryboardSegue *)myvariable;

Change default touch events for UITextField

Alright, so here is what I am trying to do. I have a UITextField. When I single tap it, I want to call one of my methods. When I double tap (tap it twice with 1 finger) it, I want to edit the text field (as though I had single tapped it on a normal UITextField.)
I am not sure how to go about this. I was thinking of sub-classing UITextField and trying to intercept the touch event as it is sent, but I can't figure out which methods to override to do this. Which methods should I override and how?
Or, if there is a better way to do this, let me know! I'm all ears, and not sure how to proceed.
This would involve several steps:
1.) Add a NSBoolean property that keeps track of whether the user has already tapped the field once recently (you get to decide what recently means here).
2.) Implement the textFieldShouldBeginEditing: method of the delegate assigned to your UITextField. If the user has tapped twice in quick succession (detectable by checking whether or not the boolean property is true), then return YES. If not, call your method, and then return NO.

Why is the MKMapView's userLocation property rubbish ... for a while?

I have a Map View defined in IB and it is set to show the user location.
In my app, in -viewDidAppear, I query self.mapView.userLocation.location.coordinate and it comes back with insane values such as:
latitude: 4.8194501961644877e-49
longitude: 2.2993313035571993e-59
However, the next time -viewDidAppear is called (after I've simply moved to another tabbed view and then back to this one) the userLocation property holds exactly the correct values for my current location.
It seems that at the time of my initial call, the userLocation property has not been initialised but despite having read Apple's documentation I can't see any caveats where it says that this property is only valid after doing xxx.
Is there something that has to happen before userLocation is valid to use or should I just use CLLocationManager and ask it instead?
Thanks in advance for any help.
Sadly, Thomas' suggestion didn't help. What I have since discovered is:
If showsUserLocation is NO, then userLocation is never set correctly and -MapView:didUpdateUserLocation: is never called, consequently I never ever get a sensible location value.
So, to get the user's location I have to set showsUserLocation to YES, however that then means that after all my annotations have been added to the view (without including the user's location) I then calculate the required span to encompass them all and display them all at the right zoom level. After I do that though, the view jumps sideways as the Map View then automatically displays the user's location as the blue blob! As it was never included in the annotations to work out the zoom level I can't incorporate it into my calculations. Aaargh!
Note that when showsUserLocation is YES, then -MapView:didUpdateUserLocation: is called, but only after I've calculated all the coordinates of my annotations, not before!
I'm assuming it hasn't finished finding the user location - it has to work this out and it may take a while.
Instead of using it in viewDidLoad use THIS delegate method:
- (void)mapView:(MKMapView *)myMapView didUpdateUserLocation:(MKUserLocation *)userLocation;
You will need to set your mapview delegate to self. :)
Same is often true of Core Location. You'll get the last location lingering it its buffer, sometimes, or a super-broad throw-the-dart-at-the-map kind of location...
Best bet is to check the .horizontalAccuracy property of the location object and toss any that are too vague. It's good practice to just chuck the first one too.
for didUpdateUserLocation to be called you have to have...
mapView.showsUserLocation = TRUE;

How to tell when MKMapView and visible MKAnnotationView are finished drawing?

I'm displaying a MKMapView with MKAnnotations some of which are selected and showing their Annotation.
I am trying to grab an image of the displayed map and annotations using the -renderInContext.
90% of the time the Map, MKPinAnnotationView's and selected annotations are correctly captured.
The other 10% of the time the image is missing something, usually the MKPinAnnotationViews or their annotations if selected.
I've added code to deal with the Map itself loading it's map data.
But I haven't been able to track down something that would indicate to me that all of the visible MKPinAnnotationView's have been drawn
and if selected their annotations displayed??
the closest hint I've come across is the addObserver, although I haven't figured out what could be observed that would tell me when all of the drawing is done.
Thoughts?
ok I'm an idiot...
I finally tracked down the problem. In my viewForAnnotation routine in the MKMapView Delegate protocol I wasn't correctly setting values for reused MKPinAnnotationView's.
So some of the time I would reuse a view that had .canShowCallout set to YES and other times I'd reuse a view that had .canShowCallout set to NO.
.<
Try using the MKMapViewDelegate didAddAnnotationViews method.
If in that method, the drawing is still not ready for your requirements, you could then in there call your capturing method with performSelector:withObject:afterDelay:.