osmdroid API解读(十一)

osmdroid API解读(十一)

osmdroid-android org.osmdroid.views.overlay包

表示覆盖物的基类,可以在MapView的顶层显示。为了添加一个overlay,需要创建一个此类的子类实体,并添加到MapView.getOverlays()的列表中。

此类实现了类似于android.view.GestureDetector.SimpleOnGestureListener和GestureDetector.OnGestureListener的手势监听器。不同之处在于为方法添加了新的参数。

1. Overlay

public abstract class Overlay implements OverlayConstants {
    //静态常量
    private static AtomicInteger sOrdinal = new AtomicInteger();
    protected static final float SHADOW_X_SKEW = -0.8999999761581421f;
    protected static final float SHADOW_Y_SCALE = 0.5f;
    private static final Rect mRect = new Rect();
    //可用性
    private boolean mEnabled = true;

    //过期
    @Deprecated
    public Overlay(final Context ctx) {
    }

    public Overlay() {
    }

    /**
     * Sets whether the Overlay is marked to be enabled. This setting does nothing by default, but
     * should be checked before calling draw().
     */
    //该图层是否被标记为可用。默认为可用,在使用draw()方法前应调用
    public void setEnabled(final boolean pEnabled) {
        this.mEnabled = pEnabled;
    }

    public boolean isEnabled() {
        return this.mEnabled;
    }

    /**
     * Since the menu-chain will pass through several independent Overlays, menu IDs cannot be fixed
     * at compile time. Overlays should use this method to obtain and store a menu id for each menu
     * item at construction time. This will ensure that two overlays don't use the same id.
     *
     * @return an integer suitable to be used as a menu identifier
     */
    //由于 menu-chain 传递通过多个独立的覆盖物,menu IDs并不能在编译时固定。此方法用于为构造menu item时获取并存储一个menu id。此方法可以确保两个图层不使用相同的id。
    protected final static int getSafeMenuId() {
        return sOrdinal.getAndIncrement();
    }

    protected final static int getSafeMenuIdSequence(final int count) {
        return sOrdinal.getAndAdd(count);
    }

    //在map上绘制overlay。此方法在所有活动图层设置为shadow=true以画下阴影层调用,然后再设置shadow=false再次调用。调用者应该在调用此方法之前检查isEnabled()。默认情况下不画任何东西。
    public abstract void draw(final Canvas c, final MapView osmv, final boolean shadow);

    // ===========================================================
    // Methods
    // ===========================================================

    /**
     * Override to perform clean up of resources before shutdown. By default does nothing.
     * 
     */
    //应该被复写在关闭之前执行清理资源工作
    public void onDetach(final MapView mapView) {
    }

    //默认情况下不做任何时,返回false。如果你处理了则返回true。若返回true,其他图层将对此事件不做任何处理。
    public boolean onKeyDown(final int keyCode, final KeyEvent event, final MapView mapView) {
        return false;
    }

    public boolean onKeyUp(final int keyCode, final KeyEvent event, final MapView mapView) {
        return false;
    }

    public boolean onTrackballEvent(final MotionEvent event, final MapView mapView) {
        return false;
    }

    //利用此可阻止触摸相关的的事件。
    public boolean onTouchEvent(final MotionEvent event, final MapView mapView) {
        return false;
    }


    /** GestureDetector.OnDoubleTapListener **/
    public boolean onDoubleTap(final MotionEvent e, final MapView mapView) {
        return false;
    }

    public boolean onDoubleTapEvent(final MotionEvent e, final MapView mapView) {
        return false;
    }
    public boolean onSingleTapConfirmed(final MotionEvent e, final MapView mapView) {
        return false;
    }

    /** OnGestureListener **/
    public boolean onDown(final MotionEvent e, final MapView mapView) {
        return false;
    }

    public boolean onFling(final MotionEvent pEvent1, final MotionEvent pEvent2,
            final float pVelocityX, final float pVelocityY, final MapView pMapView) {
        return false;
    }

    public boolean onLongPress(final MotionEvent e, final MapView mapView) {
        return false;
    }

    public boolean onScroll(final MotionEvent pEvent1, final MotionEvent pEvent2,
            final float pDistanceX, final float pDistanceY, final MapView pMapView) {
        return false;
    }

    public void onShowPress(final MotionEvent pEvent, final MapView pMapView) {
        return;
    }

    public boolean onSingleTapUp(final MotionEvent e, final MapView mapView) {
        return false;
    }

    //方便平移画Drawable的方法,x、y时像素坐标。你可以通过MapView.getProjection()方法将经纬度坐标转换为像素坐标。
    protected synchronized static void drawAt(final Canvas canvas, final Drawable drawable,
                                              final int x, final int y, final boolean shadow,
                                              final float aMapOrientation) {
        canvas.save();
        canvas.rotate(-aMapOrientation, x, y);
        drawable.copyBounds(mRect);
        drawable.setBounds(mRect.left + x, mRect.top + y, mRect.right + x, mRect.bottom + y);
        drawable.draw(canvas);
        drawable.setBounds(mRect);
        canvas.restore();
    }

    /**
     * Interface definition for overlays that contain items that can be snapped to (for example,
     * when the user invokes a zoom, this could be called allowing the user to snap the zoom to an
     * interesting point.)
     */
    //用于对overlays的包含项进行改变。比如当使用者调用缩放,允许使用者将缩放水平调整到相应的值。
    public interface Snappable {

        //检查给定的x、y是否接近于某个项,从而将当前动作调整到此项上
        boolean onSnapToItem(int x, int y, Point snapPoint, IMapView mapView);
    }

}

1.1 IconOverlay

图标型Overlay,可以在Overlay中放入一个icon

public class IconOverlay extends Overlay {
    //通常icon在像素坐标系中的位置
    public static final float ANCHOR_CENTER=0.5f, ANCHOR_LEFT=0.0f, ANCHOR_TOP=0.0f, ANCHOR_RIGHT=1.0f, ANCHOR_BOTTOM=1.0f;

    protected Drawable mIcon        = null;//图标
    protected IGeoPoint mPosition   = null;//位置

    protected float mBearing = 0.0f;
    protected float mAnchorU = ANCHOR_CENTER , mAnchorV=ANCHOR_CENTER;
    protected float mAlpha = 1.0f; //opaque

    protected boolean mFlat = false; //billboard;

    protected Point mPositionPixels = new Point();

    public IconOverlay() {
    }

    public IconOverlay(IGeoPoint position, Drawable icon) {
        set(position, icon);
    }

    //画图标到图上
    @Override
    public void draw(Canvas canvas, MapView mapView, boolean shadow) {
        if (shadow)
            return;
        if (mIcon == null)
            return;
        if (mPosition == null)
            return;

        final Projection pj = mapView.getProjection();

        pj.toPixels(mPosition, mPositionPixels);
        int width = mIcon.getIntrinsicWidth();
        int height = mIcon.getIntrinsicHeight();
        Rect rect = new Rect(0, 0, width, height);
        rect.offset(-(int)(mAnchorU*width), -(int)(mAnchorV*height));
        mIcon.setBounds(rect);

        mIcon.setAlpha((int) (mAlpha * 255));

        float rotationOnScreen = (mFlat ? -mBearing : mapView.getMapOrientation()-mBearing);
        drawAt(canvas, mIcon, mPositionPixels.x, mPositionPixels.y, false, rotationOnScreen);
    }

    public IGeoPoint getPosition() {
        return mPosition;
    }

    public IconOverlay set(IGeoPoint position, Drawable icon) {
        this.mPosition = position;
        this.mIcon = icon;
        return this;
    }

    public IconOverlay moveTo(final MotionEvent event, final MapView mapView){
        final Projection pj = mapView.getProjection();
        moveTo(pj.fromPixels((int) event.getX(), (int) event.getY()), mapView);
        return this;
    }

    public IconOverlay moveTo(final IGeoPoint position, final MapView mapView){
        mPosition = position;
        mapView.invalidate();
        return this;
    }
}

1.1.1 ClickableIconOverlay

可点击图标的Overlay,在IconOverlay基础上添加了点击处理机制

public abstract class ClickableIconOverlay<DataType> extends IconOverlay {
    protected int mId = 0;
    private DataType mData = null;

    //非UI线程创建
    protected ClickableIconOverlay(DataType data) {
        mData = data;
    }

    //标记被点击回调方法
    abstract protected boolean onMarkerClicked(MapView mapView, int markerId, IGeoPoint makerPosition, DataType markerData);

    //回收利用本类
    public ClickableIconOverlay set(int id, IGeoPoint position, Drawable icon, DataType data) {
        set(position, icon);
        mId = id;
        mData = data;
        return this;
    }

    //确定该点是否是该图标的事件
    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;
    }


    //处理单次tap事件
    @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);
        }
    }

    //处理长按事件,本类中并未处理
    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;
    }
}

1.2 关于ItemOverlay

1.2.0 OverlayItem

可以被显示在ItemizedOverlay或ItemizedIconOverlay的选项。描述了一个有标题和描述的坐标

public class OverlayItem {

    public static final int ITEM_STATE_FOCUSED_MASK = 4;
    public static final int ITEM_STATE_PRESSED_MASK = 1;
    public static final int ITEM_STATE_SELECTED_MASK = 2;

    protected static final Point DEFAULT_MARKER_SIZE = new Point(26, 94);

    public enum HotspotPlace {
        NONE, CENTER, BOTTOM_CENTER, TOP_CENTER, RIGHT_CENTER, LEFT_CENTER, UPPER_RIGHT_CORNER, LOWER_RIGHT_CORNER, UPPER_LEFT_CORNER, LOWER_LEFT_CORNER
    }

    protected final String mUid;
    protected final String mTitle;
    protected final String mSnippet;
    protected final IGeoPoint mGeoPoint;
    protected Drawable mMarker;
    protected HotspotPlace mHotspotPlace;

    public OverlayItem(final String aTitle, final String aSnippet, final IGeoPoint aGeoPoint) {
        this(null, aTitle, aSnippet, aGeoPoint);
    }

    public OverlayItem(final String aUid, final String aTitle, final String aDescription,
            final IGeoPoint aGeoPoint) {
        this.mTitle = aTitle;
        this.mSnippet = aDescription;
        this.mGeoPoint = aGeoPoint;
        this.mUid = aUid;
    }

    //Get & Set 要标记的的图标
    public Drawable getMarker(final int stateBitset) {
        // marker not specified
        if (mMarker == null) {
            return null;
        }

        // set marker state appropriately
        setState(mMarker, stateBitset);
        return mMarker;
    }

    public void setMarker(final Drawable marker) {
        this.mMarker = marker;
    }

    //设置相应状态的图片以匹配相应状态的bitset
    public static void setState(final Drawable drawable, final int stateBitset) {
        final int[] states = new int[3];
        int index = 0;
        if ((stateBitset & ITEM_STATE_PRESSED_MASK) > 0)
            states[index++] = android.R.attr.state_pressed;
        if ((stateBitset & ITEM_STATE_SELECTED_MASK) > 0)
            states[index++] = android.R.attr.state_selected;
        if ((stateBitset & ITEM_STATE_FOCUSED_MASK) > 0)
            states[index++] = android.R.attr.state_focused;

        drawable.setState(states);
    }

    public Drawable getDrawable() {
        return this.mMarker;
    }

    public int getWidth() {
        return this.mMarker.getIntrinsicWidth();
    }

    public int getHeight() {
        return this.mMarker.getIntrinsicHeight();
    }

    ...

}

1.2.1 ItemizedOverlay

画一系列的标志点到图上。具有低索引的item最后被画,因此作为顶端标记。它也首先检查ontap。这个类是通用类,因此你可以自定义ItemizedOverlay子类,并用ontap()回传。

public abstract class ItemizedOverlay<Item extends OverlayItem> extends Overlay implements
        Overlay.Snappable {

    protected final Drawable mDefaultMarker;//默认的图标
    private final ArrayList<Item> mInternalItemList;//内部点
    private boolean[] mInternalItemDisplayedList;//确定是否显示
    private final Rect mRect = new Rect();
    private final Point mCurScreenCoords = new Point();
    protected boolean mDrawFocusedItem = true;
    private Item mFocusedItem;
    private boolean mPendingFocusChangedEvent = false;
    private OnFocusChangeListener mOnFocusChangeListener;
    private final float[] mMatrixValues = new float[9];
    private final Matrix mMatrix = new Matrix();
    protected float scaleX=1f;
    protected float scaleY=1f;


    protected abstract Item createItem(int i);

    @Deprecated
    public ItemizedOverlay(Context ctx, final Drawable pDefaultMarker) {
        this(pDefaultMarker);
    }

    public ItemizedOverlay(final Drawable pDefaultMarker) {

        super();
        if (pDefaultMarker == null) {
            throw new IllegalArgumentException("You must pass a default marker to ItemizedOverlay.");
        }

        this.mDefaultMarker = pDefaultMarker;

        mInternalItemList = new ArrayList<Item>();
    }


    @Override
    public void onDetach(MapView mapView){
        if (mDefaultMarker!=null){
            //release the bitmap
        }
    }

    @Override
    public void draw(Canvas canvas, MapView mapView, boolean shadow) {

        if (shadow) {
            return;
        }

        if (mPendingFocusChangedEvent && mOnFocusChangeListener != null)
            mOnFocusChangeListener.onFocusChanged(this, mFocusedItem);
        mPendingFocusChangedEvent = false;

        final Projection pj = mapView.getProjection();
        final int size = this.mInternalItemList.size();
        if (mInternalItemDisplayedList == null || mInternalItemDisplayedList.length != size) {
            mInternalItemDisplayedList = new boolean[size];
        }

          canvas.getMatrix(mMatrix);//获取画布的矩阵
          mMatrix.getValues(mMatrixValues);//將值clone到mMatrixValues中
            //确定缩放比例
          scaleX = (float) Math.sqrt(mMatrixValues[Matrix.MSCALE_X]
               * mMatrixValues[Matrix.MSCALE_X] + mMatrixValues[Matrix.MSKEW_Y]
               * mMatrixValues[Matrix.MSKEW_Y]);
          scaleY = (float) Math.sqrt(mMatrixValues[Matrix.MSCALE_Y]
               * mMatrixValues[Matrix.MSCALE_Y] + mMatrixValues[Matrix.MSKEW_X]
               * mMatrixValues[Matrix.MSKEW_X]);
        /* Draw in backward cycle, so the items with the least index are on the front. */
        for (int i = size - 1; i >= 0; i--) {
            final Item item = getItem(i);
            if (item == null) {
                continue;
            }

            pj.toPixels(item.getPoint(), mCurScreenCoords);

            mInternalItemDisplayedList[i] = onDrawItem(canvas,item, mCurScreenCoords, mapView.getMapOrientation());
        }
    }

     //子类利用createItem(int)后,在使用其它方法前,应立即使用该方法
    protected final void populate() {
        final int size = size();
        mInternalItemList.clear();
        mInternalItemList.ensureCapacity(size);
        for (int a = 0; a < size; a++) {
            mInternalItemList.add(createItem(a));
        }
        mInternalItemDisplayedList = null;
    }


    获取某位置的选项
    public final Item getItem(final int position) {
        try {
            return mInternalItemList.get(position);
        }catch(final IndexOutOfBoundsException e) {
            return null;
        }
    }


    //将一个item画到画布上
    protected boolean onDrawItem(final Canvas canvas, final Item item, final Point curScreenCoords,
            final float aMapOrientation) {



        final int state = (mDrawFocusedItem && (mFocusedItem == item) ? OverlayItem.ITEM_STATE_FOCUSED_MASK
                : 0);
        final Drawable marker = (item.getMarker(state) == null) ? getDefaultMarker(state) : item
                .getMarker(state);
        final HotspotPlace hotspot = item.getMarkerHotspot();

        boundToHotspot(marker, hotspot);

        int x = mCurScreenCoords.x;
        int y = mCurScreenCoords.y;

        canvas.save();
        canvas.rotate(-aMapOrientation, x, y);
        marker.copyBounds(mRect);
        marker.setBounds(mRect.left + x, mRect.top + y, mRect.right + x, mRect.bottom + y);
        canvas.scale(1 / scaleX, 1 / scaleY, x, y);
        final boolean displayed = Rect.intersects(marker.getBounds(), canvas.getClipBounds());
        if (displayed) {
            marker.draw(canvas);
        }
        marker.setBounds(mRect);
        canvas.restore();
        return displayed;
        /*
        final int state = (mDrawFocusedItem && (mFocusedItem == item) ? OverlayItem.ITEM_STATE_FOCUSED_MASK
                : 0);
        final Drawable marker = (item.getMarker(state) == null) ? getDefaultMarker(state) : item
                .getMarker(state);
        final HotspotPlace hotspot = item.getMarkerHotspot();

        boundToHotspot(marker, hotspot);

        // draw it
        Overlay.drawAt(canvas, marker, curScreenCoords.x, curScreenCoords.y, false, aMapOrientation);*/
    }

    //获取显示的选项列表
    public List<Item> getDisplayedItems() {
        final List<Item> result = new ArrayList<>();
        if (mInternalItemDisplayedList == null) {
            return result;
        }
        for (int i = 0 ; i < mInternalItemDisplayedList.length ; i ++) {
            if (mInternalItemDisplayedList[i]) {
                result.add(getItem(i));
            }
        }
        return result;
    }
    //获取默认的图片
    protected Drawable getDefaultMarker(final int state) {
        OverlayItem.setState(mDefaultMarker, state);
        return mDefaultMarker;
    }


    protected boolean hitTest(final Item item, final android.graphics.drawable.Drawable marker, final int hitX,
            final int hitY) {
        return marker.getBounds().contains(hitX, hitY);
    }

    @Override
    public boolean onSingleTapConfirmed(MotionEvent e, MapView mapView) {
        final Projection pj = mapView.getProjection();
        final Rect screenRect = pj.getIntrinsicScreenRect();
        final int size = this.size();

        for (int i = 0; i < size; i++) {
            final Item item = getItem(i);
            if (item == null) {
                continue;
            }

            pj.toPixels(item.getPoint(), mCurScreenCoords);

            final int state = (mDrawFocusedItem && (mFocusedItem == item) ?
                    OverlayItem.ITEM_STATE_FOCUSED_MASK : 0);
            final Drawable marker = (item.getMarker(state) == null) ?
                    getDefaultMarker(state) : item.getMarker(state);
            boundToHotspot(marker, item.getMarkerHotspot());
            if (hitTest(item, marker, -mCurScreenCoords.x + screenRect.left + (int) e.getX(),
                    -mCurScreenCoords.y + screenRect.top + (int) e.getY())) {
                // We have a hit, do we get a response from onTap?
                if (onTap(i)) {
                    // We got a response so consume the event
                    return true;
                }
            }
        }

        return super.onSingleTapConfirmed(e, mapView);
    }

    protected boolean onTap(int index) {
        return false;
    }

    public void setDrawFocusedItem(final boolean drawFocusedItem) {
        mDrawFocusedItem = drawFocusedItem;
    }

    public void setFocus(final Item item) {
        mPendingFocusChangedEvent = item != mFocusedItem;
        mFocusedItem = item;
    }

    public Item getFocus() {
        return mFocusedItem;
    }

    protected synchronized Drawable boundToHotspot(final Drawable marker, HotspotPlace hotspot) {
        final int markerWidth = marker.getIntrinsicWidth();
        final int markerHeight = marker.getIntrinsicHeight();

        mRect.set(0, 0, 0 + markerWidth, 0 + markerHeight);

        if (hotspot == null) {
            hotspot = HotspotPlace.BOTTOM_CENTER;
        }

        switch (hotspot) {
        default:
        case NONE:
            break;
        case CENTER:
            mRect.offset(-markerWidth / 2, -markerHeight / 2);
            break;
        case BOTTOM_CENTER:
            mRect.offset(-markerWidth / 2, -markerHeight);
            break;
        case TOP_CENTER:
            mRect.offset(-markerWidth / 2, 0);
            break;
        case RIGHT_CENTER:
            mRect.offset(-markerWidth, -markerHeight / 2);
            break;
        case LEFT_CENTER:
            mRect.offset(0, -markerHeight / 2);
            break;
        case UPPER_RIGHT_CORNER:
            mRect.offset(-markerWidth, 0);
            break;
        case LOWER_RIGHT_CORNER:
            mRect.offset(-markerWidth, -markerHeight);
            break;
        case UPPER_LEFT_CORNER:
            mRect.offset(0, 0);
            break;
        case LOWER_LEFT_CORNER:
            mRect.offset(0, -markerHeight);
            break;
        }
        marker.setBounds(mRect);
        return marker;
    }

    public void setOnFocusChangeListener(OnFocusChangeListener l) {
        mOnFocusChangeListener = l;
    }

    public static interface OnFocusChangeListener {
        void onFocusChanged(ItemizedOverlay<?> overlay, OverlayItem newFocus);
    }
}

1.2.1.1 ItemizedIconOverlay

带有icon item的Overlay。

public class ItemizedIconOverlay<Item extends OverlayItem> extends ItemizedOverlay<Item> {

    ...
}

1.2.1.2 ItemizedOverlayWithFocus

有焦点的、带有icon item的Overlay。

public class ItemizedOverlayWithFocus<Item extends OverlayItem> extends ItemizedIconOverlay<Item> {

    ...
}

1.2.2 ItemizedOverlayControlView

用于ItemizedOverlay中item的的控制。

public class ItemizedOverlayControlView extends LinearLayout {

    protected ImageButton mPreviousButton;
    protected ImageButton mNextButton;
    protected ImageButton mCenterToButton;
    protected ImageButton mNavToButton;

    protected ItemizedOverlayControlViewListener mLis;

    ...

    public interface ItemizedOverlayControlViewListener {
        public void onPrevious();

        public void onNext();

        public void onCenter();

        public void onNavTo();
    }
}

1.3 MapEventsOverlay

用于检查地图事件的空覆盖物,并把事件传递给MapEventsReceiver

public class MapEventsOverlay extends Overlay {

    private MapEventsReceiver mReceiver;


    @Deprecated
    public MapEventsOverlay(Context ctx, MapEventsReceiver receiver) {
        this(receiver);
    }

    //传递一个地图事件接收者
    public MapEventsOverlay(MapEventsReceiver receiver) {
        super();
        mReceiver = receiver;
    }

    @Override public void draw(Canvas c, MapView osmv, boolean shadow) {
        //Nothing to draw
    }

    @Override public boolean onSingleTapConfirmed(MotionEvent e, MapView mapView){
        Projection proj = mapView.getProjection();
        GeoPoint p = (GeoPoint)proj.fromPixels((int)e.getX(), (int)e.getY());
        return mReceiver.singleTapConfirmedHelper(p);
    }

    @Override public boolean onLongPress(MotionEvent e, MapView mapView) {
        Projection proj = mapView.getProjection();
        GeoPoint p = (GeoPoint)proj.fromPixels((int)e.getX(), (int)e.getY());
        //throw event to the receiver:
        return mReceiver.longPressHelper(p);
    }

}

1.4 NonAcceleratedOverlay

将不兼容硬件加速的Overlay用于硬件加速的MapView。它会为Overlay创建一个屏幕尺寸的位图,然后再画Bitmap到硬件加速的canvas上。由于有多余的工作,所以不会画shadow图层

public abstract class NonAcceleratedOverlay extends Overlay {

    ...
}

1.5 OverlayWithIW

一个包含title、snippet、description的Overlay,这些信息可以在一个弹出的InfoWindow窗口中显示,处理tap事件并在相应的位置显示InfoWindow。

public abstract class OverlayWithIW extends Overlay {

    //InfoWindow handling
    protected String mTitle, mSnippet, mSubDescription;
    protected InfoWindow mInfoWindow;
    protected Object mRelatedObject;

    ...
}

1.5.1 Marker

marker是一个放在特殊点的icon,可以弹出InfoWindow

  • icon可以是任何Android标准的Drawable
  • icon可以随时改变
  • InfoWindow持有标准的Android View,它可以像处理Android组件如按钮等
  • 支持sub-description,显示在snippet下以小的字体显示在InfoWindow中。
  • 支持在InfoWindow中显示图片。
  • 支持触摸marker后将地图居中在marker位置
  • 如果使用的是同一个InfoWindow打开一个InfoWindow自动关闭其他的InfoWindow显示
  • 事件监听应该设置给每一个marker

    public class Marker extends OverlayWithIW {

    ...
    

    }

1.5.2 Polyline

Polyline是一个点列表,线段连接点与点。

public class Polyline extends OverlayWithIW {

    ...
}

1.5.3 polygon

polygon是地球表面的多边形,可以有一个弹出的InfoWindow。

public class Polygon extends OverlayWithIW {

...

}

1.5.3.1 LinearRing

多边形区域的轮廓线,或多边形区域的一个洞。

class LinearRing implements SegmentClipper.SegmentClippable{

    ...
}

1.6 ScaleBarOverlay

比例尺Overlay

public class ScaleBarOverlay extends Overlay implements GeoConstants {
    ...
}

1.7 ZoomButtonsOverlay

替换标准的ZoomButtonsController

public class ZoomButtonsOverlay extends Overlay {
    ...
}

1.8 CopyrightOverlay

所有权Overlay

public class CopyrightOverlay extends Overlay {
    ...
}

2 多个Overlay的管理与使用

2.1 OverlayManager

Overlay管理者,用于管理多个

public interface OverlayManager extends List<Overlay> {
    ...
}   

2.1.1 DefaultOverlayManager

默认的瓦片管理者需要添加一个地图式瓦片Overlay以及多个Overlay。

public class DefaultOverlayManager extends AbstractList<Overlay> implements OverlayManager {

private TilesOverlay mTilesOverlay;

private final CopyOnWriteArrayList<Overlay> mOverlayList;
    ...
}   

2.2 FolderOverlay

一个管理多个Overlay的Overlay,内部含有一个OverlayManager属性,用于真正管理多个Overlay。

public class FolderOverlay extends Overlay {

    protected OverlayManager mOverlayManager;
    protected String mName, mDescription;
    ...
}
OSMDroid 是一个开源的 Android 地图库,它允许开发者在 Android 应用程序中嵌入 OpenStreetMap 数据和地图功能。与原生 Google Maps API 不同,OSMDroid 是基于轻量级的 OSM 数据,这意味着它可以提供更好的离线地图支持,并且对隐私更加友好。 防止内存泄露(Memory Leaks)是 Android 开发中非常重要的一环,特别是在处理地图相关组件时,因为地图数据加载和绘制可能会占用大量内存。以下是一些避免 OSMDroid 防止内存泄露的方法: 1. **及时释放资源**:确保每次不再使用地图视图(MapView)、图层(Overlay)或数据源(TileProvider)时,调用相应的 `dispose()` 或 `removeAllOverlays()` 方法释放它们。 2. **使用弱引用**:对于持有地图对象的引用,可以考虑使用 WeakReference,这样即使其他强引用消失,弱引用也不会阻止垃圾回收。 3. **监听生命周期**:地图视图的 `OnDestroy()` 或 `onSaveInstanceState()` 方法中,记得清除地图相关的回调和监听器,以防止内存泄漏。 4. **批处理操作**:尽量减少在主线程执行耗时的操作,如绘制大图层或加载大量数据,可以使用异步任务或者 `AsyncTask` 来处理。 5. **使用 LruCache**:对于频繁访问但占用空间较大的地图数据,可以使用 LruCache 来缓存,当内存不足时自动清理最久未使用的数据。 6. **跟踪内存使用**:利用 Android 的内存分析工具(如 Android Studio 的 Memory Profiler 或第三方库如 LeakCanary)定期检查应用内存状况,找出可能的泄漏点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值