Skip to content Skip to sidebar Skip to footer

How To Change GoogleMap V2 Camera Center?

I am trying to change Google map V2 camera center position to be lower to the center of the map view. So far, I've partially succeeded to achive this with the help of a few solutio

Solution 1:

You should use Map Padding, namely the setPadding(int left, int top, int right, int bottom) method:

...
public void onMapReady(GoogleMap googleMap) {
    mGoogleMap = googleMap;
    mGoogleMap.setPadding(0, dHeight, 0, 0);
    ...
}
...

where dHeight = Target_pos.y - cam_pos.y. And you should move compass button, like in this answer of Vignon with some changes for drawing compass outside of clipping region:

try {
    final ViewGroup parent = (ViewGroup) mMapFragment.getView().findViewWithTag("GoogleMapMyLocationButton").getParent();
    parent.post(new Runnable() {
        @Override
        public void run() {
            try {
                Resources r = getResources();
                //convert our dp margin into pixels
                int marginPixels = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 20, r.getDisplayMetrics());
                // Get the map compass view
                View mapCompass = parent.getChildAt(4);
                View v = mapCompass;
                while (v.getParent() != null && v.getParent() instanceof ViewGroup) {
                    ViewGroup viewGroup = (ViewGroup) v.getParent();
                    viewGroup.setClipChildren(false);
                    viewGroup.setClipToPadding(false);
                    v = viewGroup;
                }

                // create layoutParams, giving it our wanted width and height(important, by default the width is "match parent")
                RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(mapCompass.getHeight(),mapCompass.getHeight());
                // position on top right
                rlp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
                rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
                rlp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
                rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 0);
                //give compass margin
                rlp.setMargins(marginPixels, dHeight, marginPixels, marginPixels);

                mapCompass.setLayoutParams(rlp);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    });
} catch (Exception ex) {
    ex.printStackTrace();
}

Also you can try that dirty solution (see the picture)

Recenered map

is to scale height of MapFragment (MapView) to dHeight more then visible area (screen height), where:

dHeight = (int) (k * MapFragment.height)

where k = Target_pos.y / cam_pos.y . In that case map center moved exactly to your desired point (but bottom (white on picture) part of map will not be visible). Also you should move up zoom controls, because by default it also at the bottom of map and will not be visible too. You can do this like in this answer. But remember, that as per the Google Maps APIs Terms of Service, your application must not remove or obscure the Google logo or copyright notices.

Seems the right solution is to create custom view, which extends MapFragment or MapView, e.g. like in that answer and do all your every location offset calculate magic inside it.


Solution 2:

Finally I've came to the solution!!

The padding solution is good for a static map but when you want to do continuance animation on the map like in navigation, the padding causes to un expected movement in turns, especially when the map tilts and zoomed!!

The MapView size solution is the right choice here as it simply push the center of the map.

The problem with that approach is that it also pushes down the zoom control and most important the Google logo which must be visible.

So, you have to explicitly set the the zoom control and Google logo bottom margin back so they will be visible again! This without putting any padding to the map view itself.

Alternatively you can set the controls and the logo position to different corners if it's ok for your need, I've decided just to set their margins.

Here is my code:

final ViewTreeObserver observer = mapView.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            mainParentLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            int parentHeight = ((ViewGroup)mapView.getParent()).getHeight() - toolbar.getHeight();
            int mapHeight = parentHeight + parentHeight/2;
            mapView.getLayoutParams().height = mapHeight;
            int margin = mapHeight - parentHeight + 2*((int)(getResources().getDimension(R.dimen.small_image) + getResources().getDimension(R.dimen.small_pargin)));
            Log.i(TAG, "onGlobalLayout: parent height: " +  parentHeight + ", map new height: " + mapHeight + ", margin: " + margin);

            setMapControlsMargin(margin);
        }
    });

This code, waits for the map view to be shown, then it calculate the map parent view height (in my case a ConstraintLayout) then it set the map height to be parentHeight * 1.5. This will push the camera center down! Then, set the margin the Google logo and zoom controls.

 private void setMapControlsMargin(final int margin){
    try {
        //Find the Zoom controls parent 
        final ViewGroup parent = (ViewGroup) mapView.findViewWithTag("GoogleMapMyLocationButton").getParent();

        //Find the Google logo parent view group
        final ViewGroup googleLogo = (ViewGroup) mapView.findViewWithTag("GoogleWatermark").getParent();

        Log.i(TAG, "setMapControlsMargin: found Google logo " + (googleLogo != null));

        //Set the margin for the Google logo
        if (googleLogo != null) {
            FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) googleLogo.getLayoutParams();
            layoutParams.bottomMargin = margin;
        }


        parent.post(() -> {
            try {
                View zoomControls = parent.getChildAt(2);  //Zoom controls
                ViewGroup.LayoutParams layoutParams1 = zoomControls.getLayoutParams();

                //Read the zoom controls original margin, this will be added to the offset margin
                int origBotMargin = ((RelativeLayout.LayoutParams) layoutParams1).bottomMargin;
                int origRightMargin = ((RelativeLayout.LayoutParams) layoutParams1).rightMargin;


                // create layoutParams, giving it our wanted width and height(important, by default the width is "match parent")
                RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(zoomControls.getWidth(),zoomControls.getHeight());
                // position on bottom right
                rlp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE);
                rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM,  RelativeLayout.TRUE);
                //set the new margin
                rlp.setMargins(0, 0, origRightMargin, origBotMargin + margin);
                zoomControls.setLayoutParams(rlp);

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

I was helped this post to move the Google logo.


Post a Comment for "How To Change GoogleMap V2 Camera Center?"