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 ofonInterceptTouchEvent()
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
How to Play Ringtone/Alarm Sound in Android
How to Handle an Asynctask During Screen Rotation
Android. How Does Notifydatasetchanged() Method and Listviews Work
How to Change the Color of Alertdialog Title and the Color of the Line Under It
Accessing Localhost of Pc from Usb Connected Android Mobile Device
What Does Google-Services.JSON Really Do
How to Pass the Values from One Activity to Previous Activity
How to Implement Multi-Select in Recyclerview
How to Connect Android App to MySQL Database
Counting Chars in Edittext Changed Listener
Startforeground Fail After Upgrade to Android 8.1
Android: Remove Notification from Notification Bar
How to Automatically Update Application on Android
Webview Load HTML from Assets Directory
How to Keep the Screen on in My App
How to Set Custom Header in Volley Request
Com.Google.Android.Gms:Play-Services-Measurement-Base Is Being Requested by Various Other Libraries