/* * Copyright (c) 2015 by k3b. */ package org.osmdroid.views.overlay; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.view.MotionEvent; import org.osmdroid.api.IGeoPoint; import org.osmdroid.views.MapView; import org.osmdroid.views.Projection; import java.util.List; /** * {@link org.osmdroid.views.overlay.ClickableIconOverlay} is a clickable icon item on the * {@link org.osmdroid.views.MapView} containing {@link org.osmdroid.api.IGeoPoint}, * {@link ClickableIconOverlay#getID() unique id} and * {@link ClickableIconOverlay#getData() data}. * * Inspired by {@link Marker} but without the dependency to certain content and a popup-window * * Created by k3b on 17.07.2015. */ public abstract class ClickableIconOverlay<DataType> extends IconOverlay { protected int mId = 0; private DataType mData = null; /** * save to be called in non-gui-thread */ protected ClickableIconOverlay(DataType data) { mData = data; } /** * @return true if click was handeled. */ abstract protected boolean onMarkerClicked(MapView mapView, int markerId, IGeoPoint makerPosition, DataType markerData); /** used to recycle this */ public ClickableIconOverlay set(int id, IGeoPoint position, Drawable icon, DataType data) { set(position, icon); mId = id; mData = data; return this; } /** * From {@link Marker#hitTest(MotionEvent, MapView)} * @return true, if this marker was taped. */ protected boolean hitTest(final MotionEvent event, final MapView mapView){ final Projection pj = mapView.getProjection(); // sometime at higher zoomlevels pj is null if ((mPosition == null) || (mPositionPixels == null) || (pj == null)) return false; pj.toPixels(mPosition, mPositionPixels); final Rect screenRect = pj.getIntrinsicScreenRect(); int x = -mPositionPixels.x + screenRect.left + (int) event.getX(); int y = -mPositionPixels.y + screenRect.top + (int) event.getY(); boolean hit = mIcon.getBounds().contains(x, y); return hit; } /** * @return true: tap handeled. No following overlay/map should handle the event. * false: tap not handeled. A following overlay/map should handle the event. */ @Override public boolean onSingleTapConfirmed(final MotionEvent event, final MapView mapView) { boolean touched = hitTest(event, mapView); if (touched) { return onMarkerClicked(mapView, mId, mPosition, mData); } else { return super.onSingleTapConfirmed(event, mapView); } } /** * By default does nothing ({@code return false}). If you handled the Event, return {@code true} * , otherwise return {@code false}. If you returned {@code true} none of the following Overlays * or the underlying {@link MapView} has the chance to handle this event. */ public boolean onLongPress(final MotionEvent event, final MapView mapView) { boolean touched = hitTest(event, mapView); if (touched) { return onMarkerLongPress(mapView, mId, mPosition, mData); } else { return super.onLongPress(event, mapView); } } protected boolean onMarkerLongPress(MapView mapView, int markerId, IGeoPoint geoPosition, Object data) { return false; } public static ClickableIconOverlay find(List<ClickableIconOverlay> list, int id) { for (ClickableIconOverlay item : list) { if ((item != null) && (item.mId == id)) return item; } return null; } public int getID() { return mId; } public DataType getData() { return mData; } }