Fixed
Status Update
Comments
al...@gmail.com <al...@gmail.com> #2
Im not talking about markers. Im talking about map itself.
to...@gmail.com <to...@gmail.com> #3
In our case, we are using a clustering algorithm which will be invoked, if user stopps dragging around.
Because "onCameraChange()" is getting called very often, clustering happens very often. So this is not a valuable solution for us.
Because "onCameraChange()" is getting called very often, clustering happens very often. So this is not a valuable solution for us.
to...@gmail.com <to...@gmail.com> #4
Here is a possible workaround:
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:
Customized FrameLayout:
private class TouchableWrapper extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mMapIsTouched = true;
break;
case MotionEvent.ACTION_UP:
mMapIsTouched = false;
break;
}
return super.onInterceptTouchEvent(ev);
}
}
}
In your MapFragment:
@Override
public View onCreateView(LayoutInflater arg0, ViewGroup arg1, Bundle arg2) {
final FrameLayout view = (FrameLayout) super.onCreateView(arg0, arg1, arg2);
mTouchView = new TouchableWrapper(getActivity());
mTouchView.addView(view);
return mTouchView;
}
In your camera change callback method:
private final OnCameraChangeListener mOnCameraChangeListener = new OnCameraChangeListener() {
@Override
public void onCameraChange(CameraPosition cameraPosition) {
if (!mMapIsTouched) {
refreshClustering(false);
}
}
};
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:
Customized FrameLayout:
private class TouchableWrapper extends FrameLayout {
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mMapIsTouched = true;
break;
case MotionEvent.ACTION_UP:
mMapIsTouched = false;
break;
}
return super.onInterceptTouchEvent(ev);
}
}
}
In your MapFragment:
@Override
public View onCreateView(LayoutInflater arg0, ViewGroup arg1, Bundle arg2) {
final FrameLayout view = (FrameLayout) super.onCreateView(arg0, arg1, arg2);
mTouchView = new TouchableWrapper(getActivity());
mTouchView.addView(view);
return mTouchView;
}
In your camera change callback method:
private final OnCameraChangeListener mOnCameraChangeListener = new OnCameraChangeListener() {
@Override
public void onCameraChange(CameraPosition cameraPosition) {
if (!mMapIsTouched) {
refreshClustering(false);
}
}
};
al...@gmail.com <al...@gmail.com> #5
Thanks Andreas, I will look into that. Ho
cy...@gmail.com <cy...@gmail.com> #6
This is pretty much a hack :s. Changes are it won't work in future releases of the framework.
1. You're casting the returned to FrameLayout. This is unsafe and you actually don't need to.
2. Doing so will imply getView() returns a TouchableWrapper which is not the original View returned by MapFragment. Let's hope MapFragment is not internally using getView() to access to its supposed View... A proper way would be to override MapView instead and create you're own Fragment.
3. You're using onInterceptTouchEvent(MotionEvent) which may not be called if requestDisallowInterceptTouchEvent(boolean) (http://developer.android.com/reference/android/view/ViewGroup.html#requestDisallowInterceptTouchEvent(boolean) ) by a child View. Prefer using dispatchTouchEvent(MotionEvent).
1. You're casting the returned to FrameLayout. This is unsafe and you actually don't need to.
2. Doing so will imply getView() returns a TouchableWrapper which is not the original View returned by MapFragment. Let's hope MapFragment is not internally using getView() to access to its supposed View... A proper way would be to override MapView instead and create you're own Fragment.
3. You're using onInterceptTouchEvent(MotionEvent) which may not be called if requestDisallowInterceptTouchEvent(boolean) (
to...@gmail.com <to...@gmail.com> #7
#5
Thank you for your comments. I've made some changes to the code.
1. This is really unnecessarsy.
2. One solution to this issue is to hold a reference to the original content view which was generated by the MapFragment. Furthermore you then have to override getView() and to return the reference to the original content view.
3. good tip!
changed code:
@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;
}
added code:
@Override
public View getView() {
return mOriginalContentView;
}
Thank you for your comments. I've made some changes to the code.
1. This is really unnecessarsy.
2. One solution to this issue is to hold a reference to the original content view which was generated by the MapFragment. Furthermore you then have to override getView() and to return the reference to the original content view.
3. good tip!
changed code:
@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;
}
added code:
@Override
public View getView() {
return mOriginalContentView;
}
cy...@gmail.com <cy...@gmail.com> #8
I seriously think this issue should be closed. I think being notified of "drag" event is a subset of being notified of a change in the CameraPosition.
There is a need for a "CameraPosition change confirmed" callback though as described in issue #4656
There is a need for a "CameraPosition change confirmed" callback though as described in issue #4656
to...@gmail.com <to...@gmail.com> #9
In my opinion there are many reasons why it is helpful to have dedicated dragging / panning events:
- dragging or panning events are always published after an user interaction. For example the camera position can be changed programmatically without the interaction of the user.
- If a dragging / panning event occurs, the geographic center position must have changed. This is different to a camera change event as I can change the zoom level without changing the geographic position. This is the same for camera rotation or changes to the view angle.
- Usually dragging / panning events are ongoing events published as long as the user interacts with the map view. With such an event you can track the movement.
- dragging or panning events are always published after an user interaction. For example the camera position can be changed programmatically without the interaction of the user.
- If a dragging / panning event occurs, the geographic center position must have changed. This is different to a camera change event as I can change the zoom level without changing the geographic position. This is the same for camera rotation or changes to the view angle.
- Usually dragging / panning events are ongoing events published as long as the user interacts with the map view. With such an event you can track the movement.
cy...@gmail.com <cy...@gmail.com> #10
>> dragging or panning events are always published after an user interaction. For example the camera position can be changed programmatically without the interaction of the user.
I don't see the difference between a manual and programmatic change. I mean, in 99% of the cases they will have the same consequence: loading some information about the current camera target/visible are, right ?
>> If a dragging / panning event occurs, the geographic center position must have changed. This is different to a camera change event as I can change the zoom level without changing the geographic position. This is the same for camera rotation or changes to the view angle.
As I said, this is a subset of a camera change. It you want to know the map has been scrolled, just look at the current Camera target. In case it is different from the previous one, it means the map has been scrolled.
>> Usually dragging / panning events are ongoing events published as long as the user interacts with the map view. With such an event you can track the movement.
I'm OK with that. Personally, I don't see the need here but this is clearly something impossible right now as long as onCameraChanged will be fired as "un-predictably".
I don't see the difference between a manual and programmatic change. I mean, in 99% of the cases they will have the same consequence: loading some information about the current camera target/visible are, right ?
>> If a dragging / panning event occurs, the geographic center position must have changed. This is different to a camera change event as I can change the zoom level without changing the geographic position. This is the same for camera rotation or changes to the view angle.
As I said, this is a subset of a camera change. It you want to know the map has been scrolled, just look at the current Camera target. In case it is different from the previous one, it means the map has been scrolled.
>> Usually dragging / panning events are ongoing events published as long as the user interacts with the map view. With such an event you can track the movement.
I'm OK with that. Personally, I don't see the need here but this is clearly something impossible right now as long as onCameraChanged will be fired as "un-predictably".
to...@gmail.com <to...@gmail.com> #11
>> I don't see the difference between a manual and programmatic change. I mean, in 99% of the cases they will have the same consequence: loading some information about the current camera target/visible are, right ?
>> As I said, this is a subset of a camera change. It you want to know the map has been scrolled, just look at the current Camera target. In case it is different from the previous one, it means the map has been scrolled.
I think this is a question of programming style / taste. I personally like not to declare helper variables just to know whether the map center has changed or an action was performed programmatically or manual. It is nice to have. It is very welcome if a framework supports such niceties like the OnSeekBarChangeListener does (http://developer.android.com/reference/android/widget/SeekBar.OnSeekBarChangeListener.html ).
But besides the programming styles or questions of taste I had a look into Google Maps Javascript client framework and I've found that theframework supports dragging events (https://developers.google.com/maps/documentation/javascript/reference ).
Personally, I feel a need to have such kind of events. And why not to have both type of events, dragging and camera change events, in the map library?
>> As I said, this is a subset of a camera change. It you want to know the map has been scrolled, just look at the current Camera target. In case it is different from the previous one, it means the map has been scrolled.
I think this is a question of programming style / taste. I personally like not to declare helper variables just to know whether the map center has changed or an action was performed programmatically or manual. It is nice to have. It is very welcome if a framework supports such niceties like the OnSeekBarChangeListener does (
But besides the programming styles or questions of taste I had a look into Google Maps Javascript client framework and I've found that theframework supports dragging events (
Personally, I feel a need to have such kind of events. And why not to have both type of events, dragging and camera change events, in the map library?
al...@gmail.com <al...@gmail.com> #12
Googlers, please give you feedback =)
al...@gmail.com <al...@gmail.com> #13
I have used touch intercepting approach. However it is nearly impossible match cameraUpdate and onTouch (ACTION_UP) since i don't start drag animation myself.
That is why i only can use approximate dragEnd based on timer after ACTION_UP.
That is why i only can use approximate dragEnd based on timer after ACTION_UP.
ba...@gmail.com <ba...@gmail.com> #14
>> I don't see the difference between a manual and programmatic change.
In our case there is a pretty big change. By default the map follows the users current location (whenever there is a a new location update from the gps we move the map programmatically). However, we want the following to stop if the user scrolled somewhere manually.
In our case there is a pretty big change. By default the map follows the users current location (whenever there is a a new location update from the gps we move the map programmatically). However, we want the following to stop if the user scrolled somewhere manually.
ro...@gmail.com <ro...@gmail.com> #16
>>In our case there is a pretty big change. By default the map follows the users current location (whenever there is a a new location update from the gps we move the map programmatically). However, we want the following to stop if the user scrolled somewhere manually.
Actually, the google map itself handle this situation same way. click "mylocation" button in google map, it will locate you to your position, and the map camera will keep follow your moving; if you srcoll the map manually, this follow will cancel and the button will change to oringal style. So I rellay don't understand why mapfragment don't hanve this event handler.
Actually, the google map itself handle this situation same way. click "mylocation" button in google map, it will locate you to your position, and the map camera will keep follow your moving; if you srcoll the map manually, this follow will cancel and the button will change to oringal style. So I rellay don't understand why mapfragment don't hanve this event handler.
ba...@gmail.com <ba...@gmail.com> #17
>> Actually, the google map itself handle this situation
I know that and we are using that. But the onCameraChange is called every time the map is moving.
I was replying to this comment:
>> I don't see the difference between a manual and programmatic change.
My point was that in our case we NEED to know the difference (because we have to do different actions).
I know that and we are using that. But the onCameraChange is called every time the map is moving.
I was replying to this comment:
>> I don't see the difference between a manual and programmatic change.
My point was that in our case we NEED to know the difference (because we have to do different actions).
ro...@gmail.com <ro...@gmail.com> #18
>> My point was that in our case we NEED to know the difference (because we have to do different actions).
I mean what you said. I need this function too, but google leave it to himself only.
At last I use a wrapper on top of map to detect the aciton from user..
mapWrapper.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
GlobalData.isDevViewLocked = false;
});
It's nasty, trigger when any touch on map...but I havn't found another way to solve it. ^%$%#%^$
I mean what you said. I need this function too, but google leave it to himself only.
At last I use a wrapper on top of map to detect the aciton from user..
mapWrapper.setOnTouchListener(
new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
GlobalData.isDevViewLocked = false;
});
It's nasty, trigger when any touch on map...but I havn't found another way to solve it. ^%$%#%^$
db...@gmail.com <db...@gmail.com> #19
Animating the camera programmatically can take some time. If the user pans the map before the animation finished, it becomes difficult to detect that the next onCameraChange event was caused by a user. Intercepting touch events shouldn't be necessary. Another argument to onCameraChange will do - perhaps something like this:
enum Reason { PROGRAMMATIC, MANUAL }
void onCameraChange(CameraPosition cameraPosition, CameraChangeReason reason);
enum Reason { PROGRAMMATIC, MANUAL }
void onCameraChange(CameraPosition cameraPosition, CameraChangeReason reason);
ex...@gmail.com <ex...@gmail.com> #20
Thanks for your advice, but how to get this CameraChangeReason when onCameraChange happened..
should I implement onCameraChangeListener and send "PROGRAMMATIC" when I try to move map with program?
Can I write like this:
In main class:
public class Main{
public static boolean isFromUsr = true;
void moveMap(){
isFromUsr = false;
//move map
//..
}
}
In My listener:
public class myOnCameraChangeListener implements OnCameraChangeListener{
@Override
public void onCameraChange(CameraPosition arg0) {
if(Main.isFromUsr){
//from usr event
} else {
//Reset flag
Main.isFromUsr = true;
//programmatic event
}
}
}
Becuse I don't konw how to write a "void onCameraChange(CameraPosition cameraPosition, CameraChangeReason reason)" when implement base listener, if have some better solution please tell me ,thanks very much
should I implement onCameraChangeListener and send "PROGRAMMATIC" when I try to move map with program?
Can I write like this:
In main class:
public class Main{
public static boolean isFromUsr = true;
void moveMap(){
isFromUsr = false;
//move map
//..
}
}
In My listener:
public class myOnCameraChangeListener implements OnCameraChangeListener{
@Override
public void onCameraChange(CameraPosition arg0) {
if(Main.isFromUsr){
//from usr event
} else {
//Reset flag
Main.isFromUsr = true;
//programmatic event
}
}
}
Becuse I don't konw how to write a "void onCameraChange(CameraPosition cameraPosition, CameraChangeReason reason)" when implement base listener, if have some better solution please tell me ,thanks very much
db...@gmail.com <db...@gmail.com> #21
I guess I was suggesting what the Maps API developers could do to make things easier for us :)
Anyway, here's a template for how I distinguish between manual/programmatic map moves. The idea is that we can be in an intermediate state (repr. by a boolean), where the next state could be manual or programmatic mode.
=================
private boolean nextCameraChangeIsManual;
public void someProgrammaticCameraChange() {
CameraUpdate update;
update = CameraUpdateFactory.newLatLng(new LatLng(0., 0.));
googleMap.animateCamera(update, new GoogleMap.CancelableCallback() {
@Override
public void onFinish() {
nextCameraChangeIsManual = false;
}
@Override
public void onCancel() {
nextCameraChangeIsManual = true;
}});
}
public void onCameraChange(...) {
if (nextCameraChangeIsManual) {
// User caused onCameraChange...
} else {
// The next map move will be caused by user, unless we
// do another move programmatically
nextCameraChangeIsManual = true;
// onCameraChange caused by program...
}
}
=================
The key here is that every programmatic map move has to have a CancelableCallback() that updates nextCameraChangeIsManual accordingly. Hope that helps.
Anyway, here's a template for how I distinguish between manual/programmatic map moves. The idea is that we can be in an intermediate state (repr. by a boolean), where the next state could be manual or programmatic mode.
=================
private boolean nextCameraChangeIsManual;
public void someProgrammaticCameraChange() {
CameraUpdate update;
update = CameraUpdateFactory.newLatLng(new LatLng(0., 0.));
googleMap.animateCamera(update, new GoogleMap.CancelableCallback() {
@Override
public void onFinish() {
nextCameraChangeIsManual = false;
}
@Override
public void onCancel() {
nextCameraChangeIsManual = true;
}});
}
public void onCameraChange(...) {
if (nextCameraChangeIsManual) {
// User caused onCameraChange...
} else {
// The next map move will be caused by user, unless we
// do another move programmatically
nextCameraChangeIsManual = true;
// onCameraChange caused by program...
}
}
=================
The key here is that every programmatic map move has to have a CancelableCallback() that updates nextCameraChangeIsManual accordingly. Hope that helps.
ex...@gmail.com <ex...@gmail.com> #22
Thanks a lot. That's helpful!
ep...@gmail.com <ep...@gmail.com> #24
I also run into this issue during clustering. There is no issue with automatic/programmatic movement of the map, but a manual dragging triggers the onCameraChange() callback too often, so i've intercepted with time-diff. works well for me.
bs...@gmail.com <bs...@gmail.com> #25
>>I also run into this issue during clustering. There is no issue with automatic/programmatic movement of the map, but a manual dragging triggers the onCameraChange() callback too often, so i've intercepted with time-diff. works well for me.
Could you provide an example of the solution you came up with? I'm facing this same issue and I can't seem to cut down on the frequency that onCameraChanged is called.
Could you provide an example of the solution you came up with? I'm facing this same issue and I can't seem to cut down on the frequency that onCameraChanged is called.
ep...@gmail.com <ep...@gmail.com> #26
hi, I've attached a sample of anon listener wrapper implementation, you can play with CAMERA_MOVE_REACT_THRESHOLD_MS to evaluate best value for you, if its not enough, you could also add kinda autosensing though, which would adapt that threshold value to the onCameraChange() call frequency.
mi...@gmail.com <mi...@gmail.com> #27
Is this problem planned to get fixed or are we stuck with hacks? I need to do different actions depending on why camera position changed, and so far everything I've seen is a hack that works except when it fails.
st...@gmail.com <st...@gmail.com> #28
imagine you have app which does track your position on the map. GPS gives a new position update more less every second, you are animating map to move it smoothly. Now you want to make easy for user to cancel tracking of his position on map, so when user moves the map it should stop the watching. At the same time you have some buttons on the map, like zoom buttons which when user tap you do not want to stop position tracking. Many solutions here kind of provide detection of touch but using them is not reliable for situation I described. Using some kind of semaphores to detect if user is touching map right now or not and meantime you get easily 2-3 gps updates which move your map as well. or using touch on some wrapper catches every touch on anything but does not recognize real movements. I'm having hard times to just reliably stop gps position tracking on "user" map move. as it is impossible to distinguish safely from frequent programmatic map moving.
ne...@gmail.com <ne...@gmail.com> #29
Is this gonna work if i am using a regular fragment instead of a mapfragment?
bd...@gmail.com <bd...@gmail.com> #30
It would be nice to see an official recommended workaround. It would appear that there is no intention to otherwise address the issue.
bl...@gmail.com <bl...@gmail.com> #31
I am also looking for a solution to this. Every solution I've seen is very hacky.
es...@gmail.com <es...@gmail.com> #32
Any official solution?
ed...@gmail.com <ed...@gmail.com> #33
Seriously, this is a 3-year-old issue and nothing has changed ...
an...@gmail.com <an...@gmail.com> #34
I need that feature A LOT. Thx to comment #21 I was able to do that... but... it's a workaround. A simple onDrag(Start/End) would save us a lot of time. Please, please... do that for us and implement that.
js...@gmail.com <js...@gmail.com> #35
Just chiming in agreeing with the request. I need to know if a move was caused by my own animation or an interruption by the user.
st...@gmail.com <st...@gmail.com> #36
I'm amazed this hasn't yet been addressed - the most common use case (I imagine) is to mimic the behaviour of the Google Maps app to cancel track location or track location+heading by the user panning/zooming/rotating the map.
It seems very odd to have to resort to various somewhat hacky methods to accomplish this..
It seems very odd to have to resort to various somewhat hacky methods to accomplish this..
an...@gmail.com <an...@gmail.com> #37
It's quite disappointing that we still do not have any solution to trace the drag/move event of android google map. I am also facing the same issue and haven't found any perfect solution yet.
But one of the possible trick is to use the distanceTo function provided by google map to calculate the distance of the user current location and his last location based on that we can start tracking of user. for e.g. if the distance is 5 or 10 meters then animateCamera to user current location. By doing this way user can drag anywhere in to map and also tracker will follow the user.
But one of the possible trick is to use the distanceTo function provided by google map to calculate the distance of the user current location and his last location based on that we can start tracking of user. for e.g. if the distance is 5 or 10 meters then animateCamera to user current location. By doing this way user can drag anywhere in to map and also tracker will follow the user.
[Deleted User] <[Deleted User]> #38
the google maps ios sdk has this, there is a willMapMove event...
lm...@google.com <lm...@google.com> #39
The August 2016 release introduces a set of new camera change listeners for camera motion start, ongoing, and end events. You can also see why the camera is moving, whether it's caused by user gestures, built-in API animations or developer-controlled movements. For details, see the guide to camera change events:
https://developers.google.com/maps/documentation/android-api/events#camera-change-events
Also, see the release notes:
https://developers.google.com/maps/documentation/android-api/releases#august_1_2016
Also, see the release notes:
bl...@gmail.com <bl...@gmail.com> #40
Thank you so much!
sj...@gmail.com <sj...@gmail.com> #41
Thanks for implementing this!
lu...@gmail.com <lu...@gmail.com> #42
Amazing!
sk...@gmail.com <sk...@gmail.com> #43
Great!
pk...@gmail.com <pk...@gmail.com> #44
Looks like miracles really do happen!
da...@google.com <da...@google.com> #45
Sorry it took so long :)
Description
In api v1 release i was able to handle this event manually using custom overlay that handles onTouch and onDraw.
Typical use case:
Geocode address according to center of the map. I can't just use "setOnCameraChangeListener" because i need to ensure that user has put finger up and animation was completed. "setOnCameraChangeListener" will on every animation has completed.
I have tried to implement that by myself. But you don't provide access to onTouch event. I even tried to handle event on parent layout, but map handles onTouch event and doesn't pop it up in view hierarchy.