ThomQ
ThomQ

Reputation: 605

Android Google Maps API - align custom button with existing buttons

I'm trying to display a custom button on a googlemap.

<Button
        android:id="@+id/button_backHome"
        android:layout_alignParentRight="true"
        android:layout_marginTop="50dp"
        android:layout_marginRight="11.5dp"
        android:layout_height="39dp"
        android:layout_width="39dp"
        android:background="@drawable/custom_button"
         />

This displays the button directly below googlemap's Set Camera to Current location button in the top right of the screen, but obviously only on my test device. On other devices these settings don't align the button correctly.

XXHDPI (galaxy S4)

enter image description here

XHDPI (Nexus 10)

enter image description here

What would be a good solution, other then making all the buttons myself? Could I inherit the margins from the google button without knowing the style's name?

I'm pretty much at a loss here, and any help would be Much apreciated.

Thanks in advance!

Upvotes: 4

Views: 1150

Answers (2)

Andrii Omelchenko
Andrii Omelchenko

Reputation: 13343

Parent Layout for Google Maps map is RelativeLayout so best approach for custom button alignment with default Google Maps control button (for all screens) is to put that custom button into same layout as default Google Maps control button. Assume our activity with Google Maps map has layout like:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="<YOUR_PACKAGE>.MainActivity">

    <fragment
        android:id="@+id/map_fragment"
        android:name="com.google.android.gms.maps.MapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <ImageView
        android:id="@+id/custom_button"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        android:visibility="gone"
        android:src="@drawable/ic_home_target"/>

</RelativeLayout>

As custom button View is better to use ImageView, because the default buttons layouts has 9 patches padding in them (details here), or it's necessary to set additional padding to default Google Maps control button. Now it belongs to activity layout. So in onMapReady(GoogleMap googleMap) we should:

1) get parent View for default Google Maps control button;

2) remove custom button view from root activity layout;

3) add custom button view to parent View for default Google Maps control button (defined in p.1);

4) set alignment for custom button view relative to default Google Maps control button.

With Source code like this:

...
private GoogleMap mGoogleMap;
private MapFragment mMapFragment;
private ImageView mCustomButton;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mCustomButton = (ImageView) findViewById(R.id.custom_button);

    mMapFragment = (MapFragment) getFragmentManager()
            .findFragmentById(R.id.map_fragment);

    mMapFragment.getMapAsync(this);
}

@Override
public void onMapReady(GoogleMap googleMap) {
    mGoogleMap = googleMap;

    // don't forget to allow LOCATION permission
    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        int locationPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
        if (locationPermission == PackageManager.PERMISSION_GRANTED) {
            setConrolsPositions();
        } 
    } else {
        setConrolsPositions();
    }
}

void setConrolsPositions() {
    try {
        mGoogleMap.setMyLocationEnabled(true);
        mGoogleMap.getUiSettings().setMyLocationButtonEnabled(true);

        // get parent view for default Google Maps control button
        final ViewGroup parent = (ViewGroup) mMapFragment.getView().findViewWithTag("GoogleMapMyLocationButton").getParent();
        parent.post(new Runnable() {
            @Override
            public void run() {
                try {
                    // get view for default Google Maps control button
                    View defaultButton = mMapFragment.getView().findViewWithTag("GoogleMapMyLocationButton");

                    // remove custom button view from activity root layout
                    ViewGroup customButtonParent = (ViewGroup) mCustomButton.getParent();
                    customButtonParent.removeView(mCustomButton);

                    // add custom button view to Google Maps control button parent
                    ViewGroup defaultButtonParent = (ViewGroup) defaultButton.getParent();
                    defaultButtonParent.addView(mCustomButton);

                    // create layout with same size as default Google Maps control button
                    RelativeLayout.LayoutParams customButtonLayoutParams = new RelativeLayout.LayoutParams(defaultButton.getHeight(), defaultButton.getHeight());

                    // align custom button view layout relative to defaultButton
                    customButtonLayoutParams.addRule(RelativeLayout.ALIGN_LEFT, defaultButton.getId());
                    customButtonLayoutParams.addRule(RelativeLayout.BELOW, defaultButton.getId());

                    // add other settings (optional)
                    mCustomButton.setAlpha(defaultButton.getAlpha());
                    mCustomButton.setPadding(defaultButton.getPaddingLeft(), defaultButton.defaultButton(),
                            defaultButton.getPaddingRight(), defaultButton.getPaddingBottom());

                    // apply layout settings to custom button view
                    mCustomButton.setLayoutParams(customButtonLayoutParams);
                    mCustomButton.setVisibility(View.VISIBLE);


                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

and enabled Show layout boundaries option in Developer Options you should get something like that:

Aligned Custom Button

As you can see custom button has exactly same size as default button layout and placed exactly below it.

For better result it's necessary to adjust custom button glyph (padding, transparency, colors, etc.)

Or may be easiest way: don't use default Google Maps "GoogleMapMyLocationButton" button at all - set it's Enabled property to false (mGoogleMap.getUiSettings().setMyLocationButtonEnabled(false);) but use custom layout with button with same icon and functionality emulated by GoogleMap.animateCamera() on same layout with "target home" custom button.

Upvotes: 2

Rod_Algonquin
Rod_Algonquin

Reputation: 26198

You have a dpi problems in your posted image, Also in your posted xml you are only using 1 attribute values for all devices android:layout_marginRight="11.5dp" which will fail in other device with higher dpi, except the one you first tried it on.

solution:

Use the values folder with dpi click here to know about it.

What you need is to create a dimens attribute on each of the dpi folder ldpi, hdpi, etc. for the margin

sample:

<resources>
    <dimen name="margin_right">11.5dp</dimen> //this is located in hdpi values dimension
</resources>

and another in xhdpi

<resources>
   <dimen name="margin_right">greater than hdpi</dimen> //this is located in xhdpi values dimension
</resources>

to use it is to just call @dimension

android:layout_marginRight="@dimension/margin_right"

now using this solution will enable your device to pick the right value of the margin on different devices.

Upvotes: -1

Related Questions