I\'m looking to do something similar to the way Uber handles pinch zoom events. No matter where you pinch on the screen, it keeps the map centered and zooms in on the center
I had the same requirement as well. I had to understand how the events are handled in android to solve this problem, because we have to intercept the touch event for zoom and pass the scroll event to the map. To achieve this, we need a custom View over Google map View. Our custom view intercepts touch events, and decides whether to handle the follow-up events by not giving a chance for underlying map to handle or just leave the underlying map to handle all by itself.
Now code time - We need two things here - a custom fragment, a custom view.
Custom fragment
public class CustomMapFragment extends SupportMapFragment implements OnMapReadyCallback {
public View mapView = null;
public WrapperView wrapperView = null;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
mapView = super.onCreateView(inflater, parent, savedInstanceState);
wrapperView = new WrapperView(getActivity());
wrapperView.addView(mapView);
SupportMapFragment mapFragment = (SupportMapFragment) getActivity().getSupportFragmentManager().findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
return wrapperView;
}
@Override
public View getView() {
return mapView;
}
@Override
public void onMapReady(GoogleMap googleMap) {
wrapperView.setGoogleMap(googleMap);
}
Custom View
public class WrapperView extends FrameLayout {
private GoogleMap googleMap;
Activity activity = null;
ScaleGestureDetector scaleGestureDetector;
public WrapperView(Activity activity) {
super(activity);
this.activity=activity;
scaleGestureDetector = new ScaleGestureDetector(activity ,new MyOnScaleGestureListener());
}
public void setGoogleMap(GoogleMap map){
googleMap = map;
}
private boolean isZoomInProgress(MotionEvent event){
if(event.getPointerCount()>1){
return true;
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event){
return isZoomInProgress(event);
}
@Override
public boolean onTouchEvent(MotionEvent event){
return scaleGestureDetector.onTouchEvent(event);
}
public class MyOnScaleGestureListener extends
ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
float previousSpan = detector.getPreviousSpan();
float currentSpan = detector.getCurrentSpan();
float targetSpan;
if(previousSpan>currentSpan){
targetSpan = previousSpan-currentSpan;
}else{
targetSpan = currentSpan-previousSpan;
}
float scaleFactor = detector.getScaleFactor();
if (scaleFactor > 1) {
if(googleMap.getCameraPosition().zoom!=googleMap.getMaxZoomLevel()) {
for(int j=0;j<(targetSpan*2);j++){
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(googleMap.getCameraPosition().target, googleMap.getCameraPosition().zoom + 0.002f));
}
}
} else {
if (googleMap.getCameraPosition().zoom != googleMap.getMinZoomLevel()) {
for(int j=0;j<(targetSpan*2);j++){
googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(googleMap.getCameraPosition().target, googleMap.getCameraPosition().zoom - 0.002f));
}
}
}
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {}
}
Use the new custom fragment in your view like below -