Change position of Google Maps API's "My location" button
Asked Answered
V

17

85

I am using the Google Maps Android API v2, and I need a way to chance the position of the "My Location" button.

I get the "My Location" button like this:

GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
final GoogleMap map = ((SupportMapFragment) getSupportFragmentManager()
        .findFragmentById(R.id.map)).getMap();

// This gets the button
map.setMyLocationEnabled(true);
Victoriavictorian answered 23/1, 2013 at 21:38 Comment(2)
AFAIK, you don't. You adjust your layout such that the ad does not overlap the map.Pauperism
Have you looked at the setPadding() method of GoogleMap? See: developers.google.com/maps/documentation/android/…Melanoid
F
72

Just use GoogleMap.setPadding(left, top, right, bottom), which allows you to indicate parts of the map that may be obscured by other views. Setting padding re-positions the standard map controls, and camera updates will use the padded region.

https://developers.google.com/maps/documentation/android/map#map_padding

Frisco answered 7/8, 2014 at 13:50 Comment(5)
This is the best answer. findById(1) is a terrible solutionTacnaarica
The absolute clearest and best practice answer. Love it.Ac
Works well for putting the mylocation button in lower right hand corner, but as you say it messes up camera updates. How to solve that? As of now my camera always sees the bottom of the screen as the center. Do you add half the height of the screen to camera when calculating stuff?Plasmodium
I prefer the mapView.findViewWithTag("GoogleMapMyLocationButton"); solution below.Earful
Note that setPadding has lots of other side-effects that may be undesired. Most importantly, it changes the screen position of the camera target.Leroy
B
89

You can get the "My Location" button and move it, like :

public class MapFragment extends SupportMapFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View mapView = super.onCreateView(inflater, container, savedInstanceState);   

    // Get the button view 
    View locationButton = ((View) mapView.findViewById(1).getParent()).findViewById(2);

    // and next place it, for exemple, on bottom right (as Google Maps app)
    RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) locationButton.getLayoutParams();
    // position on right bottom
    rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
    rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
    rlp.setMargins(0, 0, 30, 30);
    }
}
Berber answered 23/12, 2013 at 20:48 Comment(18)
Hi @fabLouis, First of all, I wanted to thank you. Your code did move the LocationButton. I am just curious that how you figured out that button's Id? Can you explain more about this mapView.findViewById(1).getParent()).findViewById(2);. Thanks again, SHCircumscissile
yeah how did you know findViewById(1) and findViewById(2)Politics
via the Android Studio debuggerBerber
if you do this, Android Studio will say " expected resource of type id"Exteriorize
@Exteriorize Even i got the same error, But i Parsed 1 and 2 using Integer class. findViewById(Integer.parseInt("1")). If you had found better solution let me know.Conation
hmm how does RelativeLayout.ALIGN_PARENT_TOP and RelativeLayout.ALIGN_PARENT_BOTTOM equal bottom right?Vindicate
nvm i get it. RelativeLayout.ALIGN_PARENT_TOP is false which essentially negates the property.Vindicate
@Berber I've implemented your code block into the my project. Everything looks fine but my location button didn't work. Even I added setMyLocationenabled(true). How can I solve this issue ? Can you give me any idea ? ThanksAccidie
This line - ((View) mapView.findViewById(1).getParent()).findViewById(2); is giving me an error - "Expected resource of type ID" on 1 and 2 integer.Rubiaceous
Hi @fabLouis, is it possible to change the location of the directions button which appears when you click on a marker. I have a floating action button in my activity that hovers over the map and it overlays the directions button of the MapAPIEddi
Getting this runtime error . Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.ViewParent android.view.View.getParent()' on a null object referenceSolent
I've tried to align it to the bottom left but instead it goes to the same position the bottom right. layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP,0); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);Married
@Married try this: rlp.addRule(RelativeLayout.ALIGN_PARENT_END, 0); rlp.addRule(RelativeLayout.ALIGN_END, 0); rlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT); to move it to the leftDunk
Works on 9.4.0, but not in 10.0.1. mapView.findViewById(1) returns nullGyro
This line - ((View) mapView.findViewById(1).getParent()).findViewById(2); was giving me an error - "Expected resource of type ID" on 1 and 2 integer then I resolved it like this ((View) mapView.findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));Skein
Note that if you are moving the my location button, you probably also want to move the compass view that's visible when the user rotates the map.Leroy
on rlp.setMargins(0, 0, 30, 30); only the 4th param, 30 for bottom margin applies. Try changing the 3rd param to 100, it doesn't apply.Conscious
after trying all setLayoutParams(int,int,int,int), I conclude that only TOP and BOTTOM margins can be set.Conscious
F
72

Just use GoogleMap.setPadding(left, top, right, bottom), which allows you to indicate parts of the map that may be obscured by other views. Setting padding re-positions the standard map controls, and camera updates will use the padded region.

https://developers.google.com/maps/documentation/android/map#map_padding

Frisco answered 7/8, 2014 at 13:50 Comment(5)
This is the best answer. findById(1) is a terrible solutionTacnaarica
The absolute clearest and best practice answer. Love it.Ac
Works well for putting the mylocation button in lower right hand corner, but as you say it messes up camera updates. How to solve that? As of now my camera always sees the bottom of the screen as the center. Do you add half the height of the screen to camera when calculating stuff?Plasmodium
I prefer the mapView.findViewWithTag("GoogleMapMyLocationButton"); solution below.Earful
Note that setPadding has lots of other side-effects that may be undesired. Most importantly, it changes the screen position of the camera target.Leroy
F
15

This may not be the best solution, but you could place your own button over the map and handle it yourself. It would take the following:-

1) Put the map in a frameLayout and add your button on top. E.g.

<FrameLayout
    android:id="@+id/mapFrame"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >



    <fragment
        xmlns:map="http://schemas.android.com/apk/res-auto"
        android:id="@+id/mapFragment"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        class="com.google.android.gms.maps.MapFragment"
        map:mapType="normal"
        map:uiCompass="true" />

    <ImageButton
        android:id="@+id/myMapLocationButton"
        android:layout_width="36dp"
        android:layout_height="36dp"
        android:layout_gravity="bottom|right"
        android:background="@drawable/myMapLocationDrawable"
        android:contentDescription="My Location" />

</FrameLayout>

2) Edit the maps UI settings so the button doesn't appear when you call setMyLocationEnabled(true). You can do this via map.getUiSettings(). setMyLocationButtonEnabled(false);

3) Handle the click of your new button to emulate what the supplied button does. E.g. call mMap.setMyLocationEnabled(...); and pan the map to the current location.

Hope that helps, or hope someone comes a long with a simpler solution for you ;-)

Fragonard answered 23/1, 2013 at 21:59 Comment(1)
BTW for what it's worth I agree with CommonsWare, don't cover the map with an advert would be best!Fragonard
S
15

I don't fancy seeing these magic view IDs others are using, I suggest using tags to find MapViews children.

Here is my solution for placing the My Location button above the Zoom controls.

// Get map views
View location_button =_mapView.findViewWithTag("GoogleMapMyLocationButton");
View zoom_in_button = _mapView.findViewWithTag("GoogleMapZoomInButton");
View zoom_layout = (View) zoom_in_button.getParent();

// adjust location button layout params above the zoom layout
RelativeLayout.LayoutParams location_layout = (RelativeLayout.LayoutParams) location_button.getLayoutParams();
location_layout.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
location_layout.addRule(RelativeLayout.ABOVE, zoom_layout.getId());
Stranglehold answered 2/10, 2016 at 10:51 Comment(4)
For anyone wondering how to do the same for the compass, the tag is GoogleMapCompass.Leroy
Hey Cord, I don't know if you remember how to do this, but do you remember where you found the list of mapview tags? I'm looking to move some other stuff around and I really dislike the other patterns people are using.Ontina
@Ontina Iterate through the subviews of the MapView (FrameLayout) and log the tag's to get them. See here (Written in Kotlin)Presentiment
@Presentiment Thank you!!Ontina
P
14

It's already been explained above.Just a small addition to fabLouis's answer. You may also get your map view from the SupportMapFragment.

        /**
         * Move the button
         */
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager().
                findFragmentById(R.id.map);
        View mapView = mapFragment.getView();
        if (mapView != null &&
                mapView.findViewById(1) != null) {
            // Get the button view
            View locationButton = ((View) mapView.findViewById(1).getParent()).findViewById(2);
            // and next place it, on bottom right (as Google Maps app)
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
                    locationButton.getLayoutParams();
            // position on right bottom
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
            layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
            layoutParams.setMargins(0, 0, 30, 30);
        }
Pino answered 22/2, 2015 at 5:37 Comment(1)
This line - ((View) mapView.findViewById(1).getParent()).findViewById(2); was giving me an error - "Expected resource of type ID" on 1 and 2 integer then I resolved it like this ((View) mapView.findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));Skein
R
12

I solved this problem in my map fragment by re positioning my location button to the right bottom corner of view using code below, here is my Maps Activity.java :-

add this lines of code in onCreate() method,

 SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapView = mapFragment.getView();
        mapFragment.getMapAsync(this);

and here is onMapReady() code :-

@Override
        public void onMapReady(GoogleMap googleMap) {
            mMap = googleMap;
            mMap.setMyLocationEnabled(true);

            // Add a marker in Sydney and move the camera
            LatLng sydney = new LatLng(-34, 151);
            mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
            mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));

            if (mapView != null &&
                    mapView.findViewById(Integer.parseInt("1")) != null) {
                // Get the button view
                View locationButton = ((View) mapView.findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));
                // and next place it, on bottom right (as Google Maps app)
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
                        locationButton.getLayoutParams();
                // position on right bottom
                layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
                layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
                layoutParams.setMargins(0, 0, 30, 30);
            }

        }

I hope, this will solve your problem. Thanks.

Rondon answered 27/8, 2016 at 7:31 Comment(2)
Thanks worked for me. I was trying with only ALIGN_PARENT_BOTTOM but not worked for me. how this is working ?Ineducation
you need to cast (view) like mapView = (View)mapFragment.getView();Devy
A
9

First, obtain Google Map View:

 View mapView = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getView();

Then find MyLocation button (id's from Android Studio debugger):

 View btnMyLocation = ((View) mapView.findViewById(1).getParent()).findViewById(2);

Finally, just set new RelativeLayout params for MyLocation button (align parent right + center vertically in this case):

RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(80,80); // size of button in dp
    params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
    params.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
    params.setMargins(0, 0, 20, 0);
    btnMyLocation.setLayoutParams(params);

Boom! Now you can move it as you want ;)

Allurement answered 9/12, 2014 at 10:14 Comment(3)
This line - ((View) mapView.findViewById(1).getParent()).findViewById(2); is giving me an error - "Expected resource of type ID" on 1 and 2 integer.Rubiaceous
Try this - View btnMyLocation = ((View) mapView.findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));Corruption
@Nalin There is an option if you Alt-Enter on the error to disable the check (e.g. for the method).Terylene
V
8

See the method below. It lives inside a class that extends SupportMapFragment. It gets the container view for the button and displays it at the bottom, centered horizontally.

/**
     * Move my position button at the bottom of map
     */
    private void resetMyPositionButton()
    {
        //deep paths for map controls
        ViewGroup v1 = (ViewGroup)this.getView();
        ViewGroup v2 = (ViewGroup)v1.getChildAt(0);
        ViewGroup v3 = (ViewGroup)v2.getChildAt(0);
        ViewGroup v4 = (ViewGroup)v3.getChildAt(1);

        //my position button
        View position =  (View)v4.getChildAt(0);

        int positionWidth = position.getLayoutParams().width;
        int positionHeight = position.getLayoutParams().height;

        //lay out position button
        RelativeLayout.LayoutParams positionParams = new RelativeLayout.LayoutParams(positionWidth,positionHeight);
        int margin = positionWidth/5;
        positionParams.setMargins(0, 0, 0, margin);
        positionParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
        positionParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE);
        position.setLayoutParams(positionParams);
    }
Visser answered 27/2, 2013 at 10:31 Comment(1)
it's giving me java.lang.ClassCastException: maps.af.q cannot be cast to android.view.ViewGroupEmbosser
K
8

If you just want to have location indication enabled (the blue dot) but don't need default My Location button:

mGoogleMap.setMyLocationEnabled(true);
mGoogleMap.getUiSettings().setMyLocationButtonEnabled(false);

This way you can also draw your own button where you want without strange stuff like this mapView.findViewById(1).getParent()).

Kenwood answered 27/4, 2015 at 12:19 Comment(1)
Thank u very muchCaballero
V
2

I had the same problem. I ended up using the Hierarchy Viewer to identify the view used to display the button and manipulated it. Very hacky, I know, but could not figure out a different way.

Visser answered 28/1, 2013 at 6:15 Comment(1)
Could you share your solution please.Tanjatanjore
D
2

It was a bit of a struggle to get this working. But I got it done, and in the process also started to move the zoom buttons around. Here my complete code:

package com.squirrel.hkairpollution;

import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.UiSettings;
import com.google.android.gms.maps.model.LatLng;

public class MySupportMapFragment extends SupportMapFragment {

private static final String TAG = HKAirPollution.TAG;

public MySupportMapFragment() {
    return;
}

@Override
public View onCreateView(LayoutInflater arg0, ViewGroup arg1, Bundle arg2) {
    Log.v(TAG, "In overridden onCreateView.");
    View v = super.onCreateView(arg0, arg1, arg2);
    Log.v(TAG, "Initialising map.");
    initMap();
    return v;
}

@Override
 public void onViewCreated (View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    resetButtons();
}

private void initMap(){
    UiSettings settings = getMap().getUiSettings();
    settings.setAllGesturesEnabled(true);
    settings.setMyLocationButtonEnabled(true);
    LatLng latLong = new LatLng(22.320542, 114.185715);
    getMap().moveCamera(CameraUpdateFactory.newLatLngZoom(latLong,11));
}


/**
 * Move my position button at the bottom of map
 */
private void resetButtons()
{
    // Get a reference to the zoom buttons and the position button.
    ViewGroup v1 = (ViewGroup)this.getView();
    ViewGroup v2 = (ViewGroup)v1.getChildAt(0);
    ViewGroup v3 = (ViewGroup)v2.getChildAt(0);
    ViewGroup v4 = (ViewGroup)v3.getChildAt(1);

    // The My Position button
    View position =  (View)v4.getChildAt(0);
    int positionWidth = position.getLayoutParams().width;
    int positionHeight = position.getLayoutParams().height;

    // Lay out the My Position button.
    RelativeLayout.LayoutParams positionParams = new RelativeLayout.LayoutParams(positionWidth,positionHeight);
    int margin = positionWidth/5;
    positionParams.setMargins(0, 0, 0, margin);
    positionParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
    positionParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
    position.setLayoutParams(positionParams);

    // The Zoom buttons
    View zoom = (View)v4.getChildAt(2);
    int zoomWidth = zoom.getLayoutParams().width;
    int zoomHeight = zoom.getLayoutParams().height;

    // Lay out the Zoom buttons.
    RelativeLayout.LayoutParams zoomParams = new RelativeLayout.LayoutParams(zoomWidth, zoomHeight);
    zoomParams.setMargins(0, 0, 0, margin);
    zoomParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
    zoomParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
    zoom.setLayoutParams(zoomParams);
} 
}
Duodenary answered 17/3, 2013 at 17:36 Comment(0)
P
2

One way to deal with this problem. Delete default button and create your own. In OnCreate statement add the next:

GoogleMap mMap = ((MapView) inflatedView.findViewById(R.id.mapview)).getMap();
LocationManager locationManager =    
(LocationManager)getActivity().getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
String provider = locationManager.getBestProvider(criteria, false);
Location location = locationManager.getLastKnownLocation(provider);
locationManager.requestLocationUpdates(provider, 2000, 1,  this);

mMap.setMyLocationEnabled(true);
mMap.getUiSettings().setMyLocationButtonEnabled(false); // delete default button

Imagebutton imgbtn = (ImageButton) view.findViewById(R.id.imgbutton); //your button
imgbtn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new    
LatLng(location.getLatitude(),     
location.getLongitude()), 15));
        }
    });
Provolone answered 29/4, 2013 at 8:35 Comment(0)
B
2

try this code

private void resetMyPositionButton()
{
    Fragment fragment = ( (SupportMapFragment) getSupportFragmentManager().findFragmentById( R.id.map ) );
    ViewGroup v1 = (ViewGroup) fragment.getView();
    ViewGroup v2 = (ViewGroup)v1.getChildAt(0);
    ViewGroup v3 = (ViewGroup)v2.getChildAt(2);
    View position =  (View)v3.getChildAt(0);
    int positionWidth = position.getLayoutParams().width;
    int positionHeight = position.getLayoutParams().height;

    //lay out position button
    RelativeLayout.LayoutParams positionParams = new RelativeLayout.LayoutParams(positionWidth,positionHeight);
    int margin = positionWidth/5;
    positionParams.setMargins(margin, 0, 0, margin);
    positionParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
    positionParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
    position.setLayoutParams(positionParams);
}
Bobbitt answered 15/2, 2016 at 13:13 Comment(0)
A
2

This button was moved on to the left side of mapBefore, you could remove old rule of button:

@Override
public void onMapReady(final GoogleMap googleMap) {
    this.map = googleMap;
    // Show location button
    View locationButton = ((View) mapView.findViewById(Integer.parseInt("1")).getParent()).findViewById(Integer.parseInt("2"));
    RelativeLayout.LayoutParams rlp = (RelativeLayout.LayoutParams) locationButton.getLayoutParams();
    // position on right bottom
    Log.l(Arrays.toString(rlp.getRules()), L.getLogInfo());
    int[] ruleList = rlp.getRules();
    for (int i = 0; i < ruleList.length; i ++) {
        rlp.removeRule(i);
    }
    Log.l(Arrays.toString(rlp.getRules()), L.getLogInfo());
    //Do what you want to move this location button:
    rlp.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
    rlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
}
Antionetteantioxidant answered 17/9, 2017 at 3:42 Comment(0)
M
1

use this one for bottom-right location

map.setMyLocationEnabled(true); 
map.setPadding(0,1600,0,0);
Macbeth answered 19/10, 2019 at 22:32 Comment(0)
E
0

You can use following approach:

    View myLocationParent = ((View) getView().findViewById(1).getParent());
    View myLocationParentParent = ((View) myLocationParent.getParent());

    // my position button

    int positionWidth = myLocationParent.getLayoutParams().width;
    int positionHeight = myLocationParent.getLayoutParams().height;

    // lay out position button
    FrameLayout.LayoutParams positionParams = new FrameLayout.LayoutParams(
            positionWidth, positionHeight);
    positionParams.setMargins(0, 100, 0, 0);

    myLocationParent.setLayoutParams(positionParams);
Embosser answered 5/9, 2013 at 6:42 Comment(2)
how did you know that ((View) getView().findViewById(1).getParent()); would get the location view?Politics
There are a lot of great stuff in Android Studio debugger ;)Allurement
F
0

I added a line to my fragment android:layout_marginTop="?attr/actionBarSize" It helped me

Fortdefrance answered 24/9, 2018 at 23:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.