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);
Jakob Harteg
  • 9,587
  • 15
  • 56
  • 78

17 Answers17

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);
    }
}
Aman Alam
  • 11,231
  • 7
  • 46
  • 81
fabLouis
  • 1,011
  • 2
  • 9
  • 7
  • 4
    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, SH – Swan Jan 30 '14 at 09:08
  • yeah how did you know findViewById(1) and findViewById(2) – reidisaki Sep 17 '14 at 06:05
  • 4
    via the Android Studio debugger – fabLouis Sep 17 '14 at 14:12
  • 1
    if you do this, Android Studio will say " expected resource of type id" – inmyth Feb 20 '15 at 15:30
  • 11
    @inmyth 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. – Harsha Mar 23 '15 at 11:01
  • 3
    hmm how does `RelativeLayout.ALIGN_PARENT_TOP` and `RelativeLayout.ALIGN_PARENT_BOTTOM` equal bottom right? – user2968401 Apr 25 '15 at 23:06
  • nvm i get it. `RelativeLayout.ALIGN_PARENT_TOP` is `false` which essentially negates the property. – user2968401 Apr 25 '15 at 23:17
  • @fabLouis 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 ? Thanks – salih Jul 29 '15 at 16:32
  • This line - ((View) mapView.findViewById(1).getParent()).findViewById(2); is giving me an error - "Expected resource of type ID" on 1 and 2 integer. – zookastos Jul 30 '15 at 00:23
  • 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 MapAPI – Mehmet Katircioglu Sep 20 '15 at 11:31
  • 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 reference – John Oct 07 '15 at 06:06
  • 1
    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); – firetrap Dec 30 '15 at 15:54
  • @firetrap 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 left – Bertoncelj1 Jul 11 '16 at 00:21
  • Works on `9.4.0`, but not in `10.0.1`. `mapView.findViewById(1)` returns null – deathangel908 Dec 21 '16 at 14:17
  • 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")); – Zohab Ali Jan 03 '17 at 16:09
  • 1
    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. – zyamys Apr 30 '17 at 22:14
  • 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. – aLL Apr 17 '19 at 08:17
  • after trying all ```setLayoutParams(int,int,int,int)```, I conclude that only ```TOP``` and ```BOTTOM``` margins can be set. – aLL Apr 17 '19 at 08:36
71

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

Ascot Harris
  • 904
  • 8
  • 7
  • 6
    This is the best answer. findById(1) is a terrible solution – pablobaldez Jan 08 '16 at 18:32
  • The absolute clearest and best practice answer. Love it. – josefdlange Jan 30 '16 at 19:00
  • 3
    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? – riper Jun 03 '16 at 14:38
  • 4
    I prefer the mapView.findViewWithTag("GoogleMapMyLocationButton"); solution below. – ayvazj Mar 06 '17 at 05:42
  • 3
    Note that `setPadding` has lots of other side-effects that may be undesired. Most importantly, it changes the screen position of the camera target. – zyamys Mar 29 '17 at 00:15
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 ;-)

Ryan
  • 2,240
  • 17
  • 17
  • BTW for what it's worth I agree with CommonsWare, don't cover the map with an advert would be best! – Ryan Jan 23 '13 at 22:02
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);
        }
Sahil Jain
  • 629
  • 7
  • 12
  • 3
    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")); – Zohab Ali Jan 03 '17 at 16:10
14

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());
Cord Rehn
  • 1,119
  • 14
  • 22
  • 3
    For anyone wondering how to do the same for the compass, the tag is `GoogleMapCompass`. – zyamys Apr 30 '17 at 22:28
  • 1
    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. – Randy Nov 03 '17 at 20:11
  • 2
    @Randy Iterate through the subviews of the MapView (FrameLayout) and log the tag's to get them. See [here](https://gist.github.com/ElegyD/d1cf53be376dd29a7454167d5dbdb0bd) (Written in Kotlin) – ElegyD Nov 06 '17 at 13:36
  • @ElegyD Thank you!! – Randy Nov 06 '17 at 16:44
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.

Priya Jagtap
  • 1,023
  • 13
  • 19
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 ;)

Roman
  • 860
  • 14
  • 14
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);
    }
oviroa
  • 1,079
  • 2
  • 12
  • 29
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()).

fraggjkee
  • 3,524
  • 2
  • 32
  • 38
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.

oviroa
  • 1,079
  • 2
  • 12
  • 29
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);
} 
}
Wouter
  • 2,623
  • 4
  • 34
  • 43
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));
        }
    });
Daryn
  • 770
  • 9
  • 19
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);
}
Metro Polinet
  • 132
  • 1
  • 3
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);
}
nobjta_9x_tq
  • 1,205
  • 14
  • 16
1

use this one for bottom-right location

map.setMyLocationEnabled(true); 
map.setPadding(0,1600,0,0);
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);
Nayanesh Gupte
  • 2,735
  • 25
  • 37
0

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

Oleg
  • 1