Skip to content Skip to sidebar Skip to footer

Centered Zooming A Google Map Through A Wrapper?

How can i set a listener on an transparent ImageView that is above the map, to only react to pinching (zooming) events on it, while everything else like moving the map gets handled

Solution 1:

So this is how i managed to do this.

I created two classes for detecting certain events, like a fling, double tap, scroll(drag) and scale(zoom):

publicclassPinchListenerextendsScaleGestureDetector.SimpleOnScaleGestureListener {

    private GoogleMap mGoogleMap;

    publicPinchListener(GoogleMap googleMap) {
        this.mGoogleMap = googleMap;
    }

    @OverridepublicbooleanonScale(ScaleGestureDetector detector) {
        doublezoom= mGoogleMap.getCameraPosition().zoom;
        zoom = zoom + Math.log(detector.getScaleFactor()) / Math.log(1.5d);
        CameraUpdateupdate= CameraUpdateFactory.newLatLngZoom(mGoogleMap.getCameraPosition().target, (float) zoom);
        mGoogleMap.moveCamera(update);
        returntrue;
    }
}

publicclassGestureListenerextendsGestureDetector.SimpleOnGestureListener {

    private GoogleMap mGoogleMap;
    privateboolean mIsInAnimation;

    publicGestureListener(GoogleMap googleMap) {
        this.mGoogleMap = googleMap;
        mIsInAnimation = false;
    }

    @OverridepublicbooleanonScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        LatLngtarget= mGoogleMap.getCameraPosition().target;
        PointscreenPoint= mGoogleMap.getProjection().toScreenLocation(target);
        PointnewPoint=newPoint(screenPoint.x + (int) distanceX, screenPoint.y + (int) distanceY);
        LatLngmapNewTarget= mGoogleMap.getProjection().fromScreenLocation(newPoint);

        CameraUpdateupdate= CameraUpdateFactory.newLatLngZoom(
                mapNewTarget, mGoogleMap.getCameraPosition().zoom);
        mGoogleMap.moveCamera(update);
        returntrue;
    }

    @OverridepublicbooleanonDoubleTap(MotionEvent e) {
        mGoogleMap.animateCamera(CameraUpdateFactory.zoomIn(), 400, null);
        returntrue;
    }

    @OverridepublicbooleanonFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        if (mIsInAnimation) returnfalse;
        intvelocity= (int) Math.sqrt(velocityX * velocityX + velocityY * velocityY);
        if (velocity < 500) returnfalse;
        doublek1=0.002d; /*exipemental*/doublek2=0.002d;/*exipemental*/LatLngtarget= mGoogleMap.getCameraPosition().target;
        PointscreenPoint= mGoogleMap.getProjection().toScreenLocation(target);

        PointnewPoint=newPoint(screenPoint.x - (int) (velocityX * k1),
                screenPoint.y - (int) (velocityY * k1));
        LatLngmapNewTarget= mGoogleMap.getProjection().fromScreenLocation(newPoint);

        CameraUpdateupdate= CameraUpdateFactory.newLatLngZoom(
                mapNewTarget, mGoogleMap.getCameraPosition().zoom);

        tryUpdateCamera(update, (int) (velocity * k2));
        returntrue;
    }

    privatevoidtryUpdateCamera(CameraUpdate update, int animateTime) {
        mIsInAnimation = true;
        mGoogleMap.animateCamera(update, animateTime, newGoogleMap.CancelableCallback() {
            @OverridepublicvoidonFinish() {
                mIsInAnimation = false;
            }

            @OverridepublicvoidonCancel() {
                mIsInAnimation = false;
            }
        });
    }
}

I then initialized a GestureDetector and ScaleGestureDetector in my MainActivity:

ScaleGestureDetectormScaleGestureDetector=newScaleGestureDetector(this, newPinchListener(mMap));
GestureDetectormGestureDetector=newGestureDetector(this, newGestureListener(mMap));

I had already created a transparent image wrapper in my activity_main to detect all these events and then simulate them on the Google Map below, like this:

<fragment 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"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:id="@+id/map"/>

<ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/mapWrapper"
/>

And then finally in my MainActivity i created an OnTouchListener for the wrapper:

mMapWrapper = findViewById(R.id.mapWrapper);

mMapWrapper.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_DOWN:
                    mMode = Mode.DRAG;
                    mGestureDetector.onTouchEvent(event);
                    mScaleGestureDetector.onTouchEvent(event);
                    break;
                case MotionEvent.ACTION_POINTER_DOWN:
                    mMode = Mode.ZOOM;
                    mScaleGestureDetector.onTouchEvent(event);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    mMode = Mode.NONE;
                    mGestureDetector.onTouchEvent(event);
                    break;
                case MotionEvent.ACTION_MOVE:
                    if (mMode == Mode.DRAG) {
                        mGestureDetector.onTouchEvent(event);
                    } elseif (mMode == Mode.ZOOM) {
                        mScaleGestureDetector.onTouchEvent(event);
                    }
                    break;
            }

            returntrue;
        }
    });

In the last step i "feed" the right detector the events that i want. If i had not done that, the zooming would not be completely centered since sometimes onScroll(Drag) events would be called and that would move the map.

Post a Comment for "Centered Zooming A Google Map Through A Wrapper?"