Google Maps Android API V2 - Detect Touch on Map

Google Maps Android API v2 - detect touch on map

@ape wrote an answer here on how to intercept the map clicks, but I need to intercept the touches, and then he suggested the following link in a comment of its answer, How to handle onTouch event for map in Google Map API v2?.

That solution seems to be a possible workaround, but the suggested code was incomplete. For this reason I rewrote and tested it, and now it works.

Here it is the working code:

I created the class MySupportMapFragment.java

import com.google.android.gms.maps.SupportMapFragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MySupportMapFragment extends SupportMapFragment {
public View mOriginalContentView;
public TouchableWrapper mTouchView;

@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;
}
}

I even created the class TouchableWrapper.java:

import android.content.Context;
import android.view.MotionEvent;
import android.widget.FrameLayout;

public class TouchableWrapper extends FrameLayout {

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

@Override
public boolean dispatchTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:
MainActivity.mMapIsTouched = true;
break;

case MotionEvent.ACTION_UP:
MainActivity.mMapIsTouched = false;
break;
}
return super.dispatchTouchEvent(event);
}
}

In the layout I declare it this way:

<fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/mapFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_below="@+id/buttonBar"
class="com.myFactory.myApp.MySupportMapFragment"
/>

Just for test in the main Activity I wrote only the following:

public class MainActivity extends FragmentActivity {
public static boolean mMapIsTouched = false;

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

How to handle touch event on google map (MapFragment)?

You can directly add click listener and get position of touch on Map in form of Location.

 map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {

@Override

public void onMapClick(LatLng latLng) {



//Do what you want on obtained latLng

}

});

How to handle onTouch event for map in Google Map API v2?

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);
}
}
};

Touch listener on Google Map Markers Android

All markers in Google Android Maps Api v2 are clickable. You don't need to set any additional properties to your marker. What you need to do - is to register marker click callback to your googleMap and handle click within callback:

public class MarkerDemoActivity extends android.support.v4.app.FragmentActivity
implements OnMarkerClickListener{
private Marker myMarker;

private void setUpMap()
{
.......
googleMap.setOnMarkerClickListener(this);

myMarker = googleMap.addMarker(new MarkerOptions()
.position(latLng)
.title("My Spot")
.snippet("This is my spot!")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE)));
......
}

@Override
public boolean onMarkerClick(final Marker marker) {

if (marker.equals(myMarker))
{
//handle click here
}
}

}

Polygon Touch detection Google Map API V2

The problem you're trying to solve is the Point in Polygon test.

To help visualize the concept of Ray Casting:


Draw a Polygon on a piece of paper. Then, starting at any random point, draw a straight line to the right of the page. If your line intersected with your polygon an odd number of times, this means your starting point was inside the Polygon.



So, how do you do that in code?

Your polygon is comprised of a list of vertices: ArrayList<Geopoint> vertices. You need to look at each Line Segment individually, and see if your Ray intersects it

private boolean isPointInPolygon(Geopoint tap, ArrayList<Geopoint> vertices) {
int intersectCount = 0;
for(int j=0; j<vertices.size()-1; j++) {
if( rayCastIntersect(tap, vertices.get(j), vertices.get(j+1)) ) {
intersectCount++;
}
}

return (intersectCount%2) == 1); // odd = inside, even = outside;
}

private boolean rayCastIntersect(Geopoint tap, Geopoint vertA, Geopoint vertB) {

double aY = vertA.getLatitude();
double bY = vertB.getLatitude();
double aX = vertA.getLongitude();
double bX = vertB.getLongitude();
double pY = tap.getLatitude();
double pX = tap.getLongitude();

if ( (aY>pY && bY>pY) || (aY<pY && bY<pY) || (aX<pX && bX<pX) ) {
return false; // a and b can't both be above or below pt.y, and a or b must be east of pt.x
}

double m = (aY-bY) / (aX-bX); // Rise over run
double bee = (-aX) * m + aY; // y = mx + b
double x = (pY - bee) / m; // algebra is neat!

return x > pX;
}


Related Topics



Leave a reply



Submit