1
votes

In an attempt to be able to rotate the map in my app 360 degrees around the user with one finger (thing pokemon go style) I came up with the following solution.

I laid a view over the entire fragment that contains the map, and added an onTouchListener to it, as the map cannot have an onTouchListener set to it. The code below rotates the map when the user drags one finger, and it is actually working quite well.

    previousMapTouchX = 0.0f;
    previousMapTouchY = 0.0f;

    coveringView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {

            float x = motionEvent.getX();
            float y = motionEvent.getY();

            switch (motionEvent.getAction()) {

                case MotionEvent.ACTION_MOVE:

                    Log.e("MAP", "MOVE");

                    float dx = x - previousMapTouchX;
                    float dy = y - previousMapTouchY;

                    // reverse direction of rotation above the mid-line
                    if (y > coveringView.getHeight() / 2) {
                        dx = dx * -1 ;
                    }

                    // reverse direction of rotation to left of the mid-line
                    if (x < coveringView.getWidth() / 2) {
                        dy = dy * -1 ;
                    }

                    CameraUpdate cameraUpdate = CameraUpdateFactory.newCameraPosition(new CameraPosition(new LatLng(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude()),
                            googleMap.getCameraPosition().zoom, MAX_TILT,
                            googleMap.getCameraPosition().bearing + ((dx + dy) * TOUCH_SCALE_FACTOR)));

                    googleMap.moveCamera(cameraUpdate);
                    break;

                case MotionEvent.ACTION_DOWN:
                    Log.e("MAP", "DOWN");
                    return false;

            }

            previousMapTouchX = x;
            previousMapTouchY = y;
            return true;

        }
    });

The issue however is that while I can rotate the map, the markers become untouchable, because the view on top is consuming all of the touch events. So I added a case to return false if an MotionEvent.ACTION_DOWN was detected. This also works, however, since the user will obviously always perform an ACTION_DOWN action before an ACTION_MOVE action, it means the map rotation code is never reached.

I'm stuck in a situation where I can either rotate the map properly, while not being able to select the map markers, or being able to select the map markers, without being able to rotate the map.

Does anybody have any suggestions on how I may get this working? It would be so much easier if the google map could just have an onTouchListener.

1

1 Answers

1
votes

You can disable all the map gestures and dispatch the touch event from your covering view to the map view:

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
    private GoogleMap mMap;
    private View mapView;

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

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapView = mapFragment.getView(); // get the map view to dispatch touch events to it
        mapFragment.getMapAsync(this);
    }

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

        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(40, 4), 18));
        mMap.addMarker(new MarkerOptions().position(new LatLng(40, 4)).title("My marker"));

        mMap.getUiSettings().setAllGesturesEnabled(false); // disable all the map gestures

        View coveringView = findViewById(R.id.coveringView);
        coveringView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(final View view, final MotionEvent motionEvent) {
                // Do your stuff here

                mapView.dispatchTouchEvent(motionEvent); // dispatch the touch event from the covering view to the map view
                return true;
            }
        });
    }
}