My layout
Any approach that relies on map events will be laggy, so I would recommed to create a helper View
that manages all the touches and dispatches some of them to the map (panning gestures in this case).
Layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<fragment
android:id="@+id/map"
class="com.google.android.gms.maps.SupportMapFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<!-- Helper view to manage touches -->
<View
android:id="@+id/helperView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<mypackage.AnchoredImageView
android:id="@+id/pin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:contentDescription="@null"
android:src="@drawable/ic_center_pin"/>
</FrameLayout>
On the Activity:
final View mMapView = getSupportFragmentManager().findFragmentById(R.id.map).getView();
View mHelperView = findViewById(R.id.helperView);
mHelperView.setOnTouchListener(new View.OnTouchListener() {
private float scaleFactor = 1f;
@Override
public boolean onTouch(final View view, final MotionEvent motionEvent) {
if (simpleGestureDetector.onTouchEvent(motionEvent)) { // Double tap
mMap.animateCamera(CameraUpdateFactory.zoomIn()); // Fixed zoom in
} else if (motionEvent.getPointerCount() == 1) { // Single tap
mMapView.dispatchTouchEvent(motionEvent); // Propagate the event to the map (Pan)
} else if (scaleGestureDetector.onTouchEvent(motionEvent)) { // Pinch zoom
mMap.moveCamera(CameraUpdateFactory.zoomBy( // Zoom the map without panning it
(mMap.getCameraPosition().zoom * scaleFactor
- mMap.getCameraPosition().zoom) / 5));
}
return true; // Consume all the gestures
}
// Gesture detector to manage double tap gestures
private GestureDetector simpleGestureDetector = new GestureDetector(
MapsActivity.this, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(MotionEvent e) {
return true;
}
});
// Gesture detector to manage scale gestures
private ScaleGestureDetector scaleGestureDetector = new ScaleGestureDetector(
MapsActivity.this, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor = detector.getScaleFactor();
return true;
}
});
});
As the anchor of a ImageView
is the center of the image, if we use a image like a pin, the marker will apparently move because the bottom center of the image must be in the center of the map. To avoid this, we can move the image creating an anchored image view.
AnchoredImageView
public class AnchoredImageView extends ImageView {
public AnchoredImageView(Context context) {
super(context);
}
public AnchoredImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AnchoredImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
setTranslationY(-h/2);
}
}