How can I handle map move end using Google Maps for Android V2?
Asked Answered
D

11

51

I want to geocode address as soon as map center has been changed.

How can I handle map moveend with new Google Maps for Android V2? (I'm talking about the case then user drags map by finger)

Denby answered 4/12, 2012 at 11:42 Comment(2)
onTouchEvent method does not help you?Sharleensharlene
Google still doesn't have this built-in! insane..Adhesive
M
31

Here is a possible workaround for determining drag start and drag end events:

You have to extend SupportMapFragment or MapFragment. In onCreateView you have to wrap your MapView in a customized FrameLayout (in example below it is the class "TouchableWrapper"), in which you intercepts touch events and recognizes whether the map is tapped or not. If your "onCameraChange" gets called, just check whether the map view is pressed or not (in example below this is the variable "mMapIsTouched").

Example code:

UPDATE 1:

  • return original created view in getView()
  • use dispatchTouchEvent() instead of onInterceptTouchEvent()

Customized FrameLayout:

private class TouchableWrapper extends FrameLayout {

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mMapIsTouched = true;
                break;
            case MotionEvent.ACTION_UP:
                mMapIsTouched = false;
                break;
        }

        return super.dispatchTouchEvent(ev);

    }

}

In your customized MapFragment:

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

    mTouchView = new TouchableWrapper(getActivity());
    mTouchView.addView(mOriginalContentView);

    return mTouchView;
}

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

In your camera change callback method:

private final OnCameraChangeListener mOnCameraChangeListener = 
        new OnCameraChangeListener() {

    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        if (!mMapIsTouched) {
            refreshClustering(false);
        }
    }
};
Melany answered 5/12, 2012 at 16:38 Comment(9)
Hey @Alexey Zakharov, please have also a look into the Thread at Google Maps issue tracker: code.google.com/p/gmaps-api-issues/issues/…Melany
That's true. It is not guaranteed that onCameraChanged() will be invoked after you determined the ACTION_UP event. Anyway, I also hope that Google will fix this issue very soon!Melany
@Melany I get the error "The method getActivity() is undefined for the type MyMapFragment". How you declare MyMapFragment?Whitford
@Melany I examined your implementation and must admit that the event is still not fired on every map movement. Check out the demo project I prepared using your code.Telegu
Nice, but you actually don't need to implement a customized framelayout, it's enough to do setOnTouchListener(new View.OnTouchListener() ... on the framelayout with the event handling code in there.Reorder
This won't work in real world. The touch events are about "real-time" and onCameraChange is out of sync, it can even appear seconds AFTER the event. So your boolean states will be wrong in many cases (I tested that). I am experimenting with a closely related solution using ACTION_MOVE to set a boolean which is reset in onCameraChange. That might work better. However, I do not think that that solution in general will work perfectly, a perfect solution needs a change of the fragment itself to call an additional event.Stjohn
@Stjohn @Melany @Alex Zakharov, put getMap().moveCamera(CameraUpdateFactory.newCameraPosition(getMap().getCameraPosition())); after mMapIsTouched = false;. It makes onCameraChange to be executed after dispatchTouchEvent always. :DMedical
@AZ13, yes Google will fix it very soon, it is already more than 3 years this issue is there, and guess what, nothing yet.Topless
extremely helpful answer. I wish this was built in!Tashia
A
65

Check out new maps api.

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

    mMap.setOnCameraIdleListener(this);
    mMap.setOnCameraMoveStartedListener(this);
    mMap.setOnCameraMoveListener(this);
    mMap.setOnCameraMoveCanceledListener(this);

    // Show Sydney on the map.
    mMap.moveCamera(CameraUpdateFactory
            .newLatLngZoom(new LatLng(-33.87365, 151.20689), 10));
}

@Override
public void onCameraMoveStarted(int reason) {

    if (reason == OnCameraMoveStartedListener.REASON_GESTURE) {
        Toast.makeText(this, "The user gestured on the map.",
                       Toast.LENGTH_SHORT).show();
    } else if (reason == OnCameraMoveStartedListener
                            .REASON_API_ANIMATION) {
        Toast.makeText(this, "The user tapped something on the map.",
                       Toast.LENGTH_SHORT).show();
    } else if (reason == OnCameraMoveStartedListener
                            .REASON_DEVELOPER_ANIMATION) {
        Toast.makeText(this, "The app moved the camera.",
                       Toast.LENGTH_SHORT).show();
    }
}

@Override
public void onCameraMove() {
    Toast.makeText(this, "The camera is moving.",
                   Toast.LENGTH_SHORT).show();
}

@Override
public void onCameraMoveCanceled() {
    Toast.makeText(this, "Camera movement canceled.",
                   Toast.LENGTH_SHORT).show();
}

@Override
public void onCameraIdle() {
    Toast.makeText(this, "The camera has stopped moving.",
                   Toast.LENGTH_SHORT).show();
}

developers.google.com sample

Avunculate answered 5/8, 2016 at 8:15 Comment(1)
Perfect solution !Wohlert
M
31

Here is a possible workaround for determining drag start and drag end events:

You have to extend SupportMapFragment or MapFragment. In onCreateView you have to wrap your MapView in a customized FrameLayout (in example below it is the class "TouchableWrapper"), in which you intercepts touch events and recognizes whether the map is tapped or not. If your "onCameraChange" gets called, just check whether the map view is pressed or not (in example below this is the variable "mMapIsTouched").

Example code:

UPDATE 1:

  • return original created view in getView()
  • use dispatchTouchEvent() instead of onInterceptTouchEvent()

Customized FrameLayout:

private class TouchableWrapper extends FrameLayout {

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mMapIsTouched = true;
                break;
            case MotionEvent.ACTION_UP:
                mMapIsTouched = false;
                break;
        }

        return super.dispatchTouchEvent(ev);

    }

}

In your customized MapFragment:

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

    mTouchView = new TouchableWrapper(getActivity());
    mTouchView.addView(mOriginalContentView);

    return mTouchView;
}

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

In your camera change callback method:

private final OnCameraChangeListener mOnCameraChangeListener = 
        new OnCameraChangeListener() {

    @Override
    public void onCameraChange(CameraPosition cameraPosition) {
        if (!mMapIsTouched) {
            refreshClustering(false);
        }
    }
};
Melany answered 5/12, 2012 at 16:38 Comment(9)
Hey @Alexey Zakharov, please have also a look into the Thread at Google Maps issue tracker: code.google.com/p/gmaps-api-issues/issues/…Melany
That's true. It is not guaranteed that onCameraChanged() will be invoked after you determined the ACTION_UP event. Anyway, I also hope that Google will fix this issue very soon!Melany
@Melany I get the error "The method getActivity() is undefined for the type MyMapFragment". How you declare MyMapFragment?Whitford
@Melany I examined your implementation and must admit that the event is still not fired on every map movement. Check out the demo project I prepared using your code.Telegu
Nice, but you actually don't need to implement a customized framelayout, it's enough to do setOnTouchListener(new View.OnTouchListener() ... on the framelayout with the event handling code in there.Reorder
This won't work in real world. The touch events are about "real-time" and onCameraChange is out of sync, it can even appear seconds AFTER the event. So your boolean states will be wrong in many cases (I tested that). I am experimenting with a closely related solution using ACTION_MOVE to set a boolean which is reset in onCameraChange. That might work better. However, I do not think that that solution in general will work perfectly, a perfect solution needs a change of the fragment itself to call an additional event.Stjohn
@Stjohn @Melany @Alex Zakharov, put getMap().moveCamera(CameraUpdateFactory.newCameraPosition(getMap().getCameraPosition())); after mMapIsTouched = false;. It makes onCameraChange to be executed after dispatchTouchEvent always. :DMedical
@AZ13, yes Google will fix it very soon, it is already more than 3 years this issue is there, and guess what, nothing yet.Topless
extremely helpful answer. I wish this was built in!Tashia
E
25

OUTDATED Use the new maps API instead. See answer from punksta.

After using AZ13's solution above, and running into the problem mentioned in the comments, I created the following solution, that solves the issue more reliably. However, since I am using a timer after the onRelease event to determine whether the map is still animating, there is a slight delay in this solution.

The code can be found on Github via this link: https://github.com/MadsFrandsen/MapStateListener

My solution can be used from an activity in the following way:

new MapStateListener(mMap, mMapFragment, this) {
  @Override
  public void onMapTouched() {
    // Map touched
  }

  @Override
  public void onMapReleased() {
    // Map released
  }

  @Override
  public void onMapUnsettled() {
    // Map unsettled
  }

  @Override
  public void onMapSettled() {
    // Map settled
  }
};
Explode answered 21/4, 2014 at 20:5 Comment(5)
seems working fine for me, its a nice enhancement to @Az13 solution :)Chauvin
@Mads Frandsen, Possible to share how would you combine your library with Marker setOnMarkerClickListener? I tried using your library and when press on any marker, code will always execute onMapSettled fuctionConsubstantial
@simeh Yes, I think any touch will count as unsettled. You could probably check if there was any movement before setting it as unsettled - that would avoid the onMapSettled call when it is just a click. I might be able to go through my (old) piece of code, this weekend or the next, if you haven't already solved the problem by then.Explode
@Mads Frandsen, I manage to solve this problem by combining this library with another code snippet which detects single touch. Thank you for replyingConsubstantial
Nice, but it would be a lot better if you could upload it to Maven or like jitpack.io so we can use it on gradle.Levite
D
8

I would try a onCameraChangeListener. The listener is called every time a movement of the camera is finished. The listener will also give you the new location. In my tests the listener was called pretty often during dragging maybe there is a better solution.

Diurnal answered 4/12, 2012 at 11:54 Comment(2)
I found that method, but as you said it fires very often. I only need to geocode when user stop dragging map and put his finger off. So it seems that i also need to handle touch myself. But there is no onTouch handler in new map api.Denby
@AlexeyZakharov is right, it is triggered too often causing the animation to stuck AZ13's answer is a really good one.Suh
B
6

The simplest way is to use setOnCameraIdleListener method to handle your move end state of touch listener on your map fragment. see the example below:

mMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
    @Override
    public void onCameraMoveStarted(int i) {
        mapPin.startAnimation(animZoomOut);
    }
});

mMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
    @Override
    public void onCameraIdle() {
        mapPin.startAnimation(animZoomIn);
    }
});
Baguio answered 2/12, 2017 at 11:5 Comment(0)
N
5

Starting with play-services-maps 9.4.0 you can simply use GoogleMap.OnCameraMoveStartedListener, GoogleMap.OnCameraMoveListener and GoogleMap.OnCameraIdleListener.

If, for some reason, you want to use the older API which is now deprecated you can use onCameraChangeListener. But you have to be aware of two things:

  1. onCameraChange() might be called many times while you drag the map OR only once (when dragging stopped).
  2. The camera position in the last call of onCameraChange() can be slightly different from the final camera position.

The following code takes both issues into account:

private static final int MESSAGE_ID_SAVE_CAMERA_POSITION = 1;
private static final int MESSAGE_ID_READ_CAMERA_POSITION = 2;
private CameraPosition lastCameraPosition;
private Handler handler;
private GoogleMap googleMap;

public void onMapReady(GoogleMap theGoogleMap) {
    googleMap = theGoogleMap;

    handler = new Handler() {
        public void handleMessage(Message msg) {
            if (msg.what == MESSAGE_ID_SAVE_CAMERA_POSITION) {
                lastCameraPosition = googleMap.getCameraPosition();
            } else if (msg.what == MESSAGE_ID_READ_CAMERA_POSITION) {
                if (lastCameraPosition.equals(googleMap.getCameraPosition())) {
                    Log.d(LOG, "Camera position stable");
                }
            }
        }
    };

    googleMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
        @Override
        public void onCameraChange(CameraPosition cameraPosition) {
            handler.removeMessages(MESSAGE_ID_SAVE_CAMERA_POSITION);
            handler.removeMessages(MESSAGE_ID_READ_CAMERA_POSITION);
            handler.sendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300);
            handler.sendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600);
        }
    });
}
Nazar answered 6/6, 2016 at 19:40 Comment(0)
W
3

On camera idle is what you should use now

 googleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
        @Override
        public void onCameraIdle() {
           //Called when camera movement has ended, there are no pending animations and the user has stopped interacting with the map.
        }
 });
Wulfe answered 19/10, 2017 at 14:45 Comment(0)
M
2

I have to animate my marker to center as long as the user drag the map. I have implemented it using Stas Shakirov answer

MapDragListenerFragment.class

public class MapDragListenerFragment extends Fragment implements OnMapReadyCallback, GoogleMap.OnMapLoadedCallback {

    private Context mContext;
    private SupportMapFragment supportMapFragment;
    private Marker centerMarker;
    private LatLng mapCenterLatLng;
    private TextView tvLocationName;
    private Button btnFinalizeDestination;
    private GoogleMap mGoogleMap;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_map_drag_listener, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mContext = getActivity();

        tvLocationName = (TextView) view.findViewById(R.id.tv_location_name);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        FragmentManager fm = getActivity().getSupportFragmentManager();//getChildFragmentManager();//
        supportMapFragment = (SupportMapFragment) fm.findFragmentById(R.id.map_container);
        if (supportMapFragment == null) {
            //// FIXME: 2/13/2017 crashes at casting to TouchableMapFragment
            supportMapFragment = SupportMapFragment.newInstance();
            fm.beginTransaction().replace(R.id.map_container, supportMapFragment).commit();
        }
        supportMapFragment.getMapAsync(this);

    }

    @Override
    public void onMapReady(GoogleMap googleMap) {

        if (googleMap != null) {
            mGoogleMap = googleMap;

            centerMarker = mGoogleMap.addMarker(new MarkerOptions().position(mGoogleMap.getCameraPosition().target)
                    .title("Center of Map")
                    .icon(BitmapDescriptorFactory.fromResource(R.drawable.end_green)));

            mGoogleMap.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
                @Override
                public void onCameraIdle() {
                    mapCenterLatLng = mGoogleMap.getCameraPosition().target;

                    animateMarker(centerMarker,mapCenterLatLng,false);

                    Toast.makeText(mContext, "The camera has stopped moving.",
                            Toast.LENGTH_SHORT).show();

                    String address = getCompleteAddressString(mapCenterLatLng.longitude,mapCenterLatLng.longitude);
                    tvLocationName.setText(address);
                }
            });
            mGoogleMap.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
                @Override
                public void onCameraMoveStarted(int reason) {
                    if (reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE) {
                        ///tvLocationName.setText("Lat " + mapCenterLatLng.latitude + "  Long :" + mapCenterLatLng.longitude);
                        Toast.makeText(mContext, "The user gestured on the map.",
                                Toast.LENGTH_SHORT).show();
                    } else if (reason == GoogleMap.OnCameraMoveStartedListener
                            .REASON_API_ANIMATION) {
                        Toast.makeText(mContext, "The user tapped something on the map.",
                                Toast.LENGTH_SHORT).show();
                    } else if (reason == GoogleMap.OnCameraMoveStartedListener
                            .REASON_DEVELOPER_ANIMATION) {
                        Toast.makeText(mContext, "The app moved the camera.",
                                Toast.LENGTH_SHORT).show();
                    }
                }
            });
            mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
                @Override
                public void onCameraMove() {
                    Toast.makeText(mContext, "The camera is moving.",
                            Toast.LENGTH_SHORT).show();
                }
            });
            mGoogleMap.setOnCameraMoveCanceledListener(new GoogleMap.OnCameraMoveCanceledListener() {
                @Override
                public void onCameraMoveCanceled() {
                    Toast.makeText(mContext, "Camera movement canceled.",
                            Toast.LENGTH_SHORT).show();
                }
            });

            mapCenterLatLng = mGoogleMap.getCameraPosition().target;// it should be done on MapLoaded.

            if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) !=
                    PackageManager.PERMISSION_GRANTED &&
                    ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) !=
                            PackageManager.PERMISSION_GRANTED) {
                return;
            }
            mGoogleMap.setMyLocationEnabled(true);
            mGoogleMap.animateCamera(CameraUpdateFactory.zoomTo(15));

            mGoogleMap.setOnMapLoadedCallback(this);
            mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
                @Override
                public void onCameraMove() {

                }
            });
        }
    }

    public void animateMarker(final Marker marker, final LatLng toPosition,
                              final boolean hideMarker) {
        final Handler handler = new Handler();
        final long start = SystemClock.uptimeMillis();
        Projection proj = mGoogleMap.getProjection();
        Point startPoint = proj.toScreenLocation(marker.getPosition());
        final LatLng startLatLng = proj.fromScreenLocation(startPoint);
         final long duration = 500;
        final Interpolator interpolator = new LinearInterpolator();
        handler.post(new Runnable() {
            @Override
            public void run() {
                long elapsed = SystemClock.uptimeMillis() - start;
                float t = interpolator.getInterpolation((float) elapsed
                        / duration);
                double lng = t * toPosition.longitude + (1 - t)
                        * startLatLng.longitude;
                double lat = t * toPosition.latitude + (1 - t)
                        * startLatLng.latitude;
                marker.setPosition(new LatLng(lat, lng));
                if (t < 1.0) {
                    // Post again 16ms later.
                    handler.postDelayed(this, 16);
                } else {
                    if (hideMarker) {
                        marker.setVisible(false);
                    } else {
                        marker.setVisible(true);
                    }
                }
            }
        });
    }
}

where fragment_map_drag_listener.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

        <fragment
            android:id="@+id/map_container"
            android:name="com.google.android.gms.maps.SupportMapFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <ImageView
            android:id="@+id/iv_center_overlay"
            android:layout_width="25dp"
            android:layout_height="25dp"
            android:visibility="gone"
            android:layout_centerInParent="true"
            android:src="@drawable/start_blue" />
    </RelativeLayout>


    <TextView
        android:id="@+id/tv_location_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="4dp"
        android:text="Location Name" />
</LinearLayout>

where MapDragListenerActivity

public class MapDragListenerActivity extends AppCompatActivity {

    private Context mContext;
    private static final String TAG = MapDragListenerFragment.class.getSimpleName();
    private MapDragListenerFragment mapDragListenerFragment;

    private Button selectPlaceBtn;
    public static final int PLACE_AUTOCOMPLETE_REQUEST_CODE = 1219;

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

        mContext = MapDragListenerActivity.this;

        mapDragListenerFragment = new MapDragListenerFragment();
        getSupportFragmentManager().beginTransaction()
                .replace(R.id.frame_container,//where frame_container is a FrameLayout
                        mapDragListenerFragment,
                        MapyFragment.class.getSimpleName()).commit();


        selectPlaceBtn = (Button) findViewById(R.id.btn_select_place);

        selectPlaceBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Intent intent = new PlaceAutocomplete.IntentBuilder(
                            PlaceAutocomplete.MODE_FULLSCREEN).build(MapDragListenerActivity.this);
                    startActivityForResult(intent, PLACE_AUTOCOMPLETE_REQUEST_CODE);
                } catch (GooglePlayServicesRepairableException e) {
                    e.printStackTrace();
                } catch (GooglePlayServicesNotAvailableException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if(requestCode == PLACE_AUTOCOMPLETE_REQUEST_CODE){
            if (resultCode == RESULT_OK) {
                Place place = PlaceAutocomplete.getPlace(mContext, data);
                if(mapDragListenerFragment != null && mapDragListenerFragment.isVisible())
                    mapDragListenerFragment.updateMarkerAtPosition(
                            place.getLatLng() ,place.getName().toString());

                Log.i(TAG, "Place:" + place.toString());
            } else if (resultCode == PlaceAutocomplete.RESULT_ERROR) {
                Status status = PlaceAutocomplete.getStatus(mContext, data);
                Log.i(TAG, status.getStatusMessage());
            } else if (requestCode == RESULT_CANCELED) {

            }
        }
    }
}

activity_map_drag_listener.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/btn_select_place"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Select Place" />

    <FrameLayout
        android:id="@+id/frame_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
Mistrot answered 2/10, 2017 at 10:21 Comment(0)
R
1
@Override
public boolean onTouchEvent(MotionEvent event, MapView mapView){

    if(event.getAction() == MotionEvent.ACTION_MOVE)
        return true;

    return false;
}
Runaway answered 16/6, 2014 at 20:2 Comment(1)
This question is being flagged as low quality because if its length and content. Could you add an explanation of how this solves the problem and perhaps cite the function(s) used?Leopoldeen
B
0

I think the event onclick in the map is: map.setOnMapClick... But event drag is: map.onCameraChangeListener because I call a log.e in both of that functions and it shown like onClick view and onDrag view . So just using them for you.

Beaufort answered 6/8, 2015 at 3:26 Comment(0)
I
0

Enhanced solution with an Handler inner Class in Xamarin Android, based on Tobus answer:

public void OnMapReady(GoogleMap googleMap)
{
        _googleMap = googleMap;

        if (_googleMap != null)
        {
            _cameraPositionHandler = new CameraPositionlHandler(_googleMap);

            _googleMap.CameraChange += OnCameraChanged; 

        }
}

void OnCameraChanged (object sender, GoogleMap.CameraChangeEventArgs e)
{   
    _cameraPositionHandler.RemoveMessages(MESSAGE_ID_SAVE_CAMERA_POSITION);
    _cameraPositionHandler.RemoveMessages(MESSAGE_ID_READ_CAMERA_POSITION);                 
    _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_SAVE_CAMERA_POSITION, 300);
    _cameraPositionHandler.SendEmptyMessageDelayed(MESSAGE_ID_READ_CAMERA_POSITION, 600);

}

With the following inner Class:

    private class CameraPositionlHandler :  Handler 
    {
        private CameraPosition _lastCameraPosition;
        private GoogleMap _googleMap;

        public CameraPositionlHandler (GoogleMap googleMap)
        {
            _googleMap = googleMap;
        }

        public override void HandleMessage(Message msg) 
        {
            if (_googleMap != null) 
            {
                if (msg.What == MESSAGE_ID_SAVE_CAMERA_POSITION) {
                    _lastCameraPosition = _googleMap.CameraPosition;
                } else if (msg.What == MESSAGE_ID_READ_CAMERA_POSITION) {
                    if (_lastCameraPosition.Equals(_googleMap.CameraPosition)) {
                        Console.WriteLine("Camera position stable");
                        //do what you want
                    }
                }
            }
        }
    }
Intoxicating answered 6/7, 2016 at 15:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.