Bryce Thomas Bryce Thomas - 2 months ago 11
iOS Question

Google Maps iOS SDK move "My Location" button to bottom left hand corner

Using the Google Maps for iOS SDK, the "My Location" button is by default placed in the bottom right hand corner:

enter image description here

I'd like to place it in the bottom left hand corner (yes, I realize I need to be careful not to obscure the "Google" logo there). I don't believe the SDK has an "official" way of doing this, but based on this answer I have figured out how to get a hold of the My Location button subview so that I can position it.

The part that has me confused is what values I should be giving to the My Location view's frame and/or bounds to get it where I want it. For starters, the My Location button as it currently stands has

frame.origin.x
=
-74
and
frame.origin.y
=
-54
. This is the first time I've seen negative coordinates for a
frame.origin.x
or a
frame.origin.y
and I'm not even sure how iOS handles negative coordinates. My first thought was that e.g.
frame.origin.x = -74
is equivalent to
[view superview].frame.size.width - 74
, i.e. negative value are subtracted from the width or height of the superview. But then I looked at the width and height of the superview and they're both
0.0
. Here's my code which outputs some information about both the map and the my location button frames and bounds:

- (void)loadView {
GMSCameraPosition *cam = [GMSCameraPosition cameraWithLatitude:jcuTownsvilleCenterCampusLat longitude:jcuTownsvilleCenterCampusLon zoom:17];
self.campusMap = [GMSMapView mapWithFrame:CGRectZero camera:cam];
self.campusMap.myLocationEnabled = YES;
self.campusMap.settings.myLocationButton = YES;
self.view = self.campusMap;

for (UIView *view in self.campusMap.subviews) {
NSLog(@"view.description: %@",view.description);
if ([view isKindOfClass:[UIButton class]]) {
// these four values in the conditional below are just what happen to
// be the values corresponding to the "my location button" in Google Maps
// for iOS SDK version 1.3.0.3430. They might change over time, so this
// code is somewhat fragile.
if (view.frame.size.width == 76 && view.frame.size.height == 54 &&
view.frame.origin.x == -76 && view.frame.origin.y == -54) {
NSLog(@"we may have found the 'my location' button");

NSLog(@"self.campusMap coord stats:");
NSLog(@"bounds.origin.x: %f", self.campusMap.bounds.origin.x);
NSLog(@"bounds.origin.y: %f", self.campusMap.bounds.origin.y);
NSLog(@"bounds.size.width: %f", self.campusMap.bounds.size.width);
NSLog(@"bounds.size.height: %f", self.campusMap.bounds.size.height);
NSLog(@"frame.origin.x: %f", self.campusMap.frame.origin.x);
NSLog(@"frame.origin.y: %f", self.campusMap.frame.origin.y);
NSLog(@"frame.size.width: %f", self.campusMap.frame.size.width);
NSLog(@"frame.size.height: %f", self.campusMap.frame.size.height);

NSLog(@"view coord stats:");
NSLog(@"bounds.origin.x: %f", view.bounds.origin.x);
NSLog(@"bounds.origin.y: %f", view.bounds.origin.y);
NSLog(@"bounds.size.width: %f", view.bounds.size.width);
NSLog(@"bounds.size.height: %f", view.bounds.size.height);
NSLog(@"frame.origin.x: %f", view.frame.origin.x);
NSLog(@"frame.origin.y: %f", view.frame.origin.y);
NSLog(@"frame.size.width: %f", view.frame.size.width);
NSLog(@"frame.size.height: %f", view.frame.size.height);
}
}
}
}


And here is the output:

self.campusMap coord stats:
bounds.origin.x: 0.000000
bounds.origin.y: 0.000000
bounds.size.width: 0.000000
bounds.size.height: 0.000000
frame.origin.x: 0.000000
frame.origin.y: 0.000000
frame.size.width: 0.000000
frame.size.height: 0.000000
view coord stats:
bounds.origin.x: 0.000000
bounds.origin.y: 0.000000
bounds.size.width: 76.000000
bounds.size.height: 54.000000
frame.origin.x: -76.000000
frame.origin.y: -54.000000
frame.size.width: 76.000000
frame.size.height: 54.000000


I tried as a simple test to position the "My Location" button in the top left hand corner with:

CGRect frame = view.frame;
frame.origin.x = 0;
frame.origin.y = 0;
frame.size.width = 76;
frame.size.height = 54;
[view setFrame:frame];


but then the My Location button didn't show at all.

I have also tried small modifications to the existing values (e.g. changing
frame.origin.x
from
-76.0
to
-66.0
and can see the difference in position, so at least I'm confident I'm modifying the position of the right view. I still don't understand i) how negative coordinates work and ii) how to properly position the view in this specific scenario though. After reading the answers to this question I thought I had a reasonable grasp on view frames and bounds, but given that I haven't gotten this to work yet, apparently not.

Answer

The easiest way to solve this is to change the frame and autoresizing mask of the button right after the map view is created.

UIButton* myLocationButton = (UIButton*)[[mapView_ subviews] lastObject];
myLocationButton.autoresizingMask = UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleTopMargin;
CGRect frame = myLocationButton.frame;
frame.origin.x = 5;
myLocationButton.frame = frame;

EDIT: Sorry, I placed the button in the top right corner. Updated my code to place it in the bottom left hand corner.

Note: there is currently no API from Google to get the location button. The first line may not work in future releases of the SDK.

You also should create a feature request here.

Another option is to create the button yourself and add it as a subview to the map. The button handler code is fairly easy:

  CLLocation *location = mapView_.myLocation;
  if (location) {
    [mapView_ animateToLocation:location.coordinate];
  }