Creating OnDragListener for Google Map v2 Fragment
Asked Answered
O

4

18

I’m trying to setup an onDrag Listener for a google map fragment, but can’t get the drag event to fire. Since the map doesn't support drag events directly, I'm trying to implement a drag listener for the View. I know about the onMarkerDrag event, but that does me no good since I'm not trying to move markers around.

The reason for trapping map drag events is twofold:

First to detect if the user has panned the map. If they haven't, I like to keep their location on the screen, and animate to their location if it's not on the map. If they have panned the map, I assume they know what they want to see and force the location on the screen. (this seems like something that should be included in the API)

The second reason for trapping is to allow users to draw lines and polygons on the map. I can do this with onTap events(adding points), but I'd like to be able to let them freehand it as well.

My code looks like this:

mainActivity:

    mMap = ((MapFragment) getFragmentManager().findFragmentById(R.id.map)).getMap();
    setUpMapIfNeeded();
    mMapView = findViewById(R.id.map);
    myMapDragListener = new MapDragListener();
    mMapView.setOnDragListener(myMapDragListener);

The Listener:

public class MapDragListener implements OnDragListener {
    /**
     * 
     */
    public MapDragListener() {
        super();
        say.logCat("MapDragListener: I'm ALIVE!!!!");
    }

    private AkamaiAnnounce say = new AkamaiAnnounce();
    private boolean inDrag;
    private boolean hasPanned=false;

    @Override
    public boolean onDrag(View v, DragEvent event) {
        say.logCat("MapDragListener.onDrag: " + event.toString());
        //String dotTAG = (String) getTag();
        if (event.getLocalState() != this) {
          return false;
        }
        boolean myResult = true;
        int action = event.getAction();
        float x = event.getX();
        float y = event.getY();
        switch (action) {
        case DragEvent.ACTION_DRAG_STARTED:
          inDrag = true;
          break;
        case DragEvent.ACTION_DRAG_LOCATION:
          break;
        case DragEvent.ACTION_DRAG_ENTERED:
          break;
        case DragEvent.ACTION_DRAG_EXITED:
          break;
        case DragEvent.ACTION_DROP:
          myResult = false;
          break;
        case DragEvent.ACTION_DRAG_ENDED:
          inDrag = false; // change color of original dot back
          hasPanned=true;
          break;
        default:
          myResult = false;
          break;
        }
        return false;
        //return myResult;

    }

    public boolean hasPanned() {
        return hasPanned;
    }

    public void setHasPanned(boolean hasPanned) {
        this.hasPanned = hasPanned;
    }

}

The map works fine. The listener instantiates, but my onDrag event never fires. Any ideas?

Outthink answered 20/6, 2013 at 20:27 Comment(2)
if you are talking about dragging markers, v2 certainly does have drag listeners. use implements OnMarkerDragListenerFractionize
@Fractionize It's not about dragging markers, but panning the whole map. Tim: This won't work because map consumes events. Update your question, say what you want to achieve and maybe we can find a solution.Darbies
A
24

To get drag event listener a fragment containing googleMap, one can use below method of google. We can get the target position of map.

googleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
          @Override
          public void onCameraIdle() {   
              Log.e(TAG,"==camera idle=="+ googleMap.getCameraPosition().target);

          }
      });
googleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
        @Override
        public void onCameraMoveStarted(int reason) {
            if (reason ==REASON_GESTURE) {
                isMaptouched=true;
                Toast.makeText(getActivity(), "The user gestured on the map.",
                        Toast.LENGTH_SHORT).show();
            } else if (reason ==REASON_API_ANIMATION) {
                Toast.makeText(getActivity(), "The user tapped something on the map.",
                        Toast.LENGTH_SHORT).show();
            } else if (reason ==REASON_DEVELOPER_ANIMATION) {
                Toast.makeText(getActivity(), "The app moved the camera.",
                        Toast.LENGTH_SHORT).show();
            }
        }


    });
Adallard answered 26/6, 2017 at 6:50 Comment(4)
looking for this from last few days.. :)Inhuman
Thanks, was looking for this. Just a note, used OnCameraMoveStartedListener.* to access values of REASON_API_ANIMATION, REASON_DEVELOPER_ANIMATION and REASON_GESTUREConcertgoer
I prefer this answer, clean and no extra hack aroundsPubescent
Thanks ! your answer saved my day :)Adore
A
19

1) Create wrapper class:

public class MapWrapperLayout extends FrameLayout {

    public interface OnDragListener {
        public void onDrag(MotionEvent motionEvent);
    }

    private OnDragListener mOnDragListener;

    public MapWrapperLayout(Context context) {
        super(context);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (mOnDragListener != null) {
            mOnDragListener.onDrag(ev);
        }
        return super.dispatchTouchEvent(ev);
    }

    public void setOnDragListener(OnDragListener mOnDragListener) {
        this.mOnDragListener = mOnDragListener;
    }
}

2) Create subclass of MapFragment class:

public class CustomMapFragment extends SupportMapFragment {

    private View mOriginalView;
    private MapWrapperLayout mMapWrapperLayout;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mOriginalView = super.onCreateView(inflater, container, savedInstanceState);

        mMapWrapperLayout = new MapWrapperLayout(getActivity());
        mMapWrapperLayout.addView(mOriginalView);

        return mMapWrapperLayout;
}

    @Override
    public View getView() {
        return mOriginalView;
    }

    public void setOnDragListener(MapWrapperLayout.OnDragListener onDragListener) {
        mMapWrapperLayout.setOnDragListener(onDragListener);
    }

3.1) Finally, in your activity:

    // Google map init block
    CustomMapFragment customMapFragment = ((CustomMapFragment) getSupportFragmentManager().findFragmentById(R.id.map));
    customMapFragment.setOnDragListener(new MapWrapperLayout.OnDragListener() {
        @Override
        public void onDrag(MotionEvent motionEvent) {
            Log.d("ON_DRAG", String.format("ME: %s", motionEvent));
            // Handle motion event:
        }
    });
    GoogleMap map = customMapFragment.getMap();

3.2) ... and in your layout:

<fragment android:id="@+id/map"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:name="your.package.CustomMapFragment"/>
Allover answered 31/8, 2013 at 14:54 Comment(3)
Please mind that there are still there are issues like 4636.Janenejanenna
@Allover Im following this. I m getting the Log. I want to listen only the move event . how to get this event onlyFlavorful
@QadirHussain If I understand your question exactly, then: if(motionEvent.getAction()==MotionEvent.ACTION_MOVE){...}Allover
I
2

I solved it using the onCameraMoveCancelledListener:

 mMap.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
        @Override
        public void onMapClick(LatLng latLng) {
            stopCamera=true;
        }
    });


    mMap.setOnCameraMoveCanceledListener(new GoogleMap.OnCameraMoveCanceledListener() {
        @Override
        public void onCameraMoveCanceled() {
            stopCamera = true;
        }
    });
Irritation answered 6/5, 2018 at 12:11 Comment(0)
M
1

I did something like similar using a BehaviorSubject to tell if the map was dirty (moved by user)

    storeMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
        @Override
        public void onCameraMoveStarted(int reason) {
            if (reason == REASON_GESTURE) {
                mapIsDirty.onNext(true);
            }
        }
    });
    storeMap.setOnCameraIdleListener(new OnCameraIdleListener() {
        @Override
        public void onCameraIdle() {
            if(mapIsDirty.getValue()) {
            // Do happy things
            mapIsDirty.onNext(false);
            }
        }
    });
Manipulator answered 5/12, 2017 at 21:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.