osmdroid API解读(十五)

osmdroid API解读(十五)

osmdroid-android MapView解析

public class MapView extends ViewGroup implements IMapView, MapViewConstants,
        MultiTouchObjectCanvas<Object> {

    // ===========================================================
    // Constants
    // ===========================================================

    private static final double ZOOM_SENSITIVITY = 1.0;//缩放敏感度
    private static final double ZOOM_LOG_BASE_INV = 1.0 / Math.log(2.0 / ZOOM_SENSITIVITY);
    private static Method sMotionEventTransformMethod;

    // ===========================================================
    // Fields
    // ===========================================================

    private double mZoomLevel = 0;//当前的缩放等级

    private OverlayManager mOverlayManager;//图层管理者,用于管理多个Overlay

    protected Projection mProjection;//当前的投影,用于设备屏幕坐标系与地理坐标系之间的转换

    private TilesOverlay mMapOverlay;//瓦片Overlay,用作底图

    private final GestureDetector mGestureDetector;//手势检测

    private final Scroller mScroller;//处理地图滚动
    protected boolean mIsFlinging;//地图的Flinging状态

    protected final AtomicReference<Double> mTargetZoomLevel = new AtomicReference<>();
    protected final AtomicBoolean mIsAnimating = new AtomicBoolean(false);

    protected Integer mMinimumZoomLevel;//最小缩放等级
    protected Integer mMaximumZoomLevel;//最大缩放等级

    private final MapController mController;//地图控制器,如缩放、平移等

    private MultiTouchController<Object> mMultiTouchController;//多点触摸控制
    protected float mMultiTouchScale = 1.0f;
    protected PointF mMultiTouchScalePoint = new PointF();

    protected MapListener mListener;//地图状态监听,缩放和平移

    private float mapOrientation = 0;//地图旋转角度
    private final Rect mInvalidateRect = new Rect();

    protected BoundingBox mScrollableAreaBoundingBox;
    protected RectL mScrollableAreaLimit;

    private MapTileProviderBase mTileProvider;//瓦片提供者,用于底图的数据获取
    private Handler mTileRequestCompleteHandler;//瓦片数据请求后,结果处理
    private boolean mTilesScaledToDpi = false;

    final Point mRotateScalePoint = new Point();

    private final Point mLayoutPoint = new Point();
    private final PointL mMercatorPoint = new PointL();

    // 地图布局监听
    private final LinkedList<OnFirstLayoutListener> mOnFirstLayoutListeners = new LinkedList<MapView.OnFirstLayoutListener>();

    /* becomes true once onLayout has been called for the first time i.e. map is ready to go. */
    private boolean mLayoutOccurred = false;

    private GeoPoint mCenter;
    private long mMapScrollX;
    private long mMapScrollY;

    private ZoomButtonsOverlay mZoomButtonsOverlay;
    //布局监听接口
    public interface OnFirstLayoutListener {
        /**
         * this generally means that the map is ready to go
         * @param v
         * @param left
         * @param top
         * @param right
         * @param bottom
         */
        void onFirstLayout(View v, int left, int top, int right, int bottom);
    }

    // ===========================================================
    // Constructors
    // ===========================================================

    public MapView(final Context context,
                      MapTileProviderBase tileProvider,
                      final Handler tileRequestCompleteHandler, final AttributeSet attrs) {
        this(context, tileProvider, tileRequestCompleteHandler, attrs, Configuration.getInstance().isMapViewHardwareAccelerated());

    }

    public MapView(final Context context,
                      MapTileProviderBase tileProvider,
                      final Handler tileRequestCompleteHandler, final AttributeSet attrs, boolean hardwareAccelerated) {
        super(context, attrs);
        ...
    }

    //xml布局
    public MapView(final Context context, final AttributeSet attrs) {
        this(context, null, null, attrs);
    }

    public MapView(final Context context) {
        this(context, null, null, null);
    }

    public MapView(final Context context,
                   final MapTileProviderBase aTileProvider) {
        this(context, aTileProvider, null);
    }

    public MapView(final Context context,
                   final MapTileProviderBase aTileProvider,
                   final Handler tileRequestCompleteHandler) {
        this(context, aTileProvider, tileRequestCompleteHandler,
                null);
    }

    // ===========================================================
    // Getter & Setter
    // ===========================================================

    ...

    //获取当前屏幕的边界
    public Rect getScreenRect(final Rect reuse) {
        final Rect out = getIntrinsicScreenRect(reuse);
        if (this.getMapOrientation() != 0 && this.getMapOrientation() != 180) {
            GeometryMath.getBoundingBoxForRotatatedRectangle(out, out.centerX(), out.centerY(),
                    this.getMapOrientation(), out);
        }
        return out;
    }

    public Rect getIntrinsicScreenRect(final Rect reuse) {
        final Rect out = reuse == null ? new Rect() : reuse;
        out.set(0, 0, getWidth(), getHeight());
        return out;
    }

    ...

    //设置该点为屏幕坐标系的中间位置
    @Deprecated
    void setMapCenter(final IGeoPoint aCenter) {
        getController().animateTo(aCenter);
    }

    @Deprecated
    void setMapCenter(final int aLatitudeE6, final int aLongitudeE6) {
        setMapCenter(new GeoPoint(aLatitudeE6, aLongitudeE6));
     }
     @Deprecated
    void setMapCenter(final double aLatitude, final double aLongitude) {
        setMapCenter(new GeoPoint(aLatitude, aLongitude));
    }

    public boolean isTilesScaledToDpi() {
        return mTilesScaledToDpi;
    }

    public void setTilesScaledToDpi(boolean tilesScaledToDpi) {
        mTilesScaledToDpi = tilesScaledToDpi;
        updateTileSizeForDensity(getTileProvider().getTileSource());
    }

    private void updateTileSizeForDensity(final ITileSource aTileSource) {
        int tile_size = aTileSource.getTileSizePixels();
        float density =  getResources().getDisplayMetrics().density * 256 / tile_size ;
        int size = (int) ( tile_size * (isTilesScaledToDpi() ? density : 1));
        if (Configuration.getInstance().isDebugMapView())
            Log.d(IMapView.LOGTAG, "Scaling tiles to " + size);
        TileSystem.setTileSize(size);
    }

    public void setTileSource(final ITileSource aTileSource) {
        mTileProvider.setTileSource(aTileSource);//将瓦片源设置给建好的瓦片提供者
        updateTileSizeForDensity(aTileSource);
        this.checkZoomButtons();
        this.setZoomLevel(mZoomLevel); // revalidate zoom level
        postInvalidate();
    }

    //缩放
    double setZoomLevel(final double aZoomLevel) {
        ...
        return this.mZoomLevel;
    }

    @Deprecated
    public void zoomToBoundingBox(final BoundingBoxE6 boundingBox) {
        BoundingBox box = new BoundingBox(boundingBox.getLatNorthE6()/1e6, boundingBox.getLonEastE6()/1e6, boundingBox.getLatSouthE6()/1e6, boundingBox.getLonWestE6()/1e6);
        zoomToBoundingBox(box, false);
    }

    public void zoomToBoundingBox(final BoundingBox boundingBox, final boolean animated) {
        zoomToBoundingBox(boundingBox, animated, 0);
    }

    public void zoomToBoundingBox(final BoundingBox boundingBox, final boolean animated, final int borderSizeInPixels) {
        ...
    }

    ...

    public boolean canZoomIn() {
        final int maxZoomLevel = getMaxZoomLevel();
        if ((isAnimating() ? mTargetZoomLevel.get() : mZoomLevel) >= maxZoomLevel) {
            return false;
        }
        return true;
    }

    public boolean canZoomOut() {
        final int minZoomLevel = getMinZoomLevel();
        if ((isAnimating() ? mTargetZoomLevel.get() : mZoomLevel) <= minZoomLevel) {
            return false;
        }
        return true;
    }

    /**
     * Zoom in by one zoom level.
     */
    boolean zoomIn() {
        return getController().zoomIn();
    }

    @Deprecated
    boolean zoomInFixing(final IGeoPoint point) {
        Point coords = getProjection().toPixels(point, null);
        return getController().zoomInFixing(coords.x, coords.y);
    }

    @Deprecated
    boolean zoomInFixing(final int xPixel, final int yPixel) {
        return getController().zoomInFixing(xPixel, yPixel);
    }

    /**
     * Zoom out by one zoom level.
     */
    boolean zoomOut() {
        return getController().zoomOut();
    }

    @Deprecated
    boolean zoomOutFixing(final IGeoPoint point) {
        Point coords = getProjection().toPixels(point, null);
        return zoomOutFixing(coords.x, coords.y);
    }

    @Deprecated
    boolean zoomOutFixing(final int xPixel, final int yPixel) {
        return getController().zoomOutFixing(xPixel, yPixel);
    }


    @Override
    public IGeoPoint getMapCenter() {
        return getProjection().fromPixels(getWidth() / 2, getHeight() / 2, null);
    }


    /**
     * rotates the map to the desired heading
     * @param degrees
     */
    public void setMapOrientation(float degrees) {
        setMapOrientation(degrees, true);
    }

    /**
     * There are some cases when we don't need explicit redraw
     * @since 6.0.0
     */
    public void setMapOrientation(final float degrees, final boolean forceRedraw) {
        mapOrientation = degrees % 360.0f;
        if (forceRedraw) {
            // Request a layout, so that children are correctly positioned according to map orientation
            requestLayout();
            invalidate();
        }
    }

    public float getMapOrientation() {
        return mapOrientation;
    }

    /**
     * @since 5.6.6
     */
    public float getMapScale() {
        return mMultiTouchScale;
    }

    //是否使用网络连接
    public boolean useDataConnection() {
        return mMapOverlay.useDataConnection();
    }

    public void setUseDataConnection(final boolean aMode) {
        mMapOverlay.setUseDataConnection(aMode);
    }

     @Deprecated
    public void setScrollableAreaLimit(BoundingBoxE6 boundingBox) {
         setScrollableAreaLimitDouble(boundingBox == null ? null : new BoundingBox(
                boundingBox.getLatNorthE6()/1E6, boundingBox.getLonEastE6()/1E6,
                boundingBox.getLatSouthE6()/1E6, boundingBox.getLonWestE6()/1E6));
    }

    public void setScrollableAreaLimitDouble(BoundingBox boundingBox) {
        mScrollableAreaBoundingBox = boundingBox;

        ...
    }


   ...

    //滚动
    @Override
    public void scrollBy(int x, int y) {
        scrollTo((int)(getMapScrollX() + x), (int)(getMapScrollY() + y));
    }

    //设置北京颜色
    @Override
    public void setBackgroundColor(final int pColor) {
        mMapOverlay.setLoadingBackgroundColor(pColor);
        invalidate();
    }

    @Override
    protected void dispatchDraw(final Canvas c) {
        final long startMs = System.currentTimeMillis();

        // Reset the projection
        resetProjection();

        // Save the current canvas matrix
        c.save();

        // Apply the scale and rotate operations
        c.concat(getProjection().getScaleRotateCanvasMatrix());

        /* Draw background */
        // c.drawColor(mBackgroundColor);
        try {
            /* Draw all Overlays. */
            this.getOverlayManager().onDraw(c, this);
            mZoomButtonsOverlay.draw(c, this, false);
            // Restore the canvas matrix
            c.restore();
            super.dispatchDraw(c);
        }catch (Exception ex){
            //for edit mode
            Log.e(IMapView.LOGTAG, "error dispatchDraw, probably in edit mode", ex);
        }
        if (Configuration.getInstance().isDebugMapView()) {
            final long endMs = System.currentTimeMillis();
            Log.d(IMapView.LOGTAG,"Rendering overall: " + (endMs - startMs) + "ms");
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        this.onDetach();
        super.onDetachedFromWindow();
    }

    ...

    //设置地图监听器
    public void setMapListener(final MapListener ml) {
        mListener = ml;
    }

    // ===========================================================
    // Methods 常用的功能
    // ===========================================================

    private void checkZoomButtons() {
        mZoomButtonsOverlay.setZoomInEnabled(canZoomIn());
        mZoomButtonsOverlay.setZoomOutEnabled(canZoomOut());
    }

    public void setBuiltInZoomControls(final boolean on) {
        setBuiltInZoomControls(on,
                ZoomButtonsOverlay.POSITION_HORIZONTAL_DEFAULT
                | ZoomButtonsOverlay.POSITION_VERTICAL_DEFAULT);
    }

    public void setBuiltInZoomControls(final boolean on, final int pPosition) {
        mZoomButtonsOverlay.setEnabled(on);
        mZoomButtonsOverlay.setPosition(pPosition);
        checkZoomButtons();
    }


    public void setBuiltInZoomControls(final boolean on, final int pLeft, final int pTop) {
        mZoomButtonsOverlay.setEnabled(on);
        mZoomButtonsOverlay.setLeftTop(pLeft, pTop);
        checkZoomButtons();
    }

    public void setMultiTouchControls(final boolean on) {
        mMultiTouchController = on ? new MultiTouchController<Object>(this, false) : null;
    }

    ...

    private boolean enableFling = true;
    private boolean pauseFling = false; // issue 269, boolean used for disabling fling during zoom changes
    public void setFlingEnabled(final boolean b){
        enableFling = b;
    }
    public boolean isFlingEnabled(){
        return enableFling;
    }
    // ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================

    //手势检测
    private class MapViewGestureDetectorListener implements OnGestureListener {

        @Override
        public boolean onDown(final MotionEvent e) {

            ...
            return true;
        }

        @Override
        public boolean onFling(final MotionEvent e1, final MotionEvent e2,
                    final float velocityX, final float velocityY) {
                    ...
            return true;
        }

        @Override
        public void onLongPress(final MotionEvent e) {
            ...
        }

        @Override
        public boolean onScroll(final MotionEvent e1, final MotionEvent e2, final float distanceX,
                final float distanceY) {
            ...
        }

        @Override
        public void onShowPress(final MotionEvent e) {
            ...
        }

        @Override
        public boolean onSingleTapUp(final MotionEvent e) {
            ...
        }

    }
    //双点击手势检测
    private class MapViewDoubleClickListener implements GestureDetector.OnDoubleTapListener {
        @Override
        public boolean onDoubleTap(final MotionEvent e) {
            if (MapView.this.getOverlayManager().onDoubleTap(e, MapView.this)) {
                return true;
            }

            // final IGeoPoint center = getProjection().fromPixels((int) e.getX(), (int) e.getY(),
            // null);
            getProjection().rotateAndScalePoint((int) e.getX(), (int) e.getY(), mRotateScalePoint);
            return zoomInFixing(mRotateScalePoint.x, mRotateScalePoint.y);
        }

        @Override
        public boolean onDoubleTapEvent(final MotionEvent e) {
            if (MapView.this.getOverlayManager().onDoubleTapEvent(e, MapView.this)) {
                return true;
            }

            return false;
        }

        @Override
        public boolean onSingleTapConfirmed(final MotionEvent e) {
            if (MapView.this.getOverlayManager().onSingleTapConfirmed(e, MapView.this)) {
                return true;
            }

            return false;
        }
    }

    // ===========================================================
    // Public Classes
    // ===========================================================

    /**
     * OpenStreetMapView每个子类布局
     */
    public static class LayoutParams extends ViewGroup.LayoutParams {

        ...
    }

    //使你能够设置瓦片提供者,如zip, assets, sqlite, etc
    public void setTileProvider(final  MapTileProviderBase base){
        this.mTileProvider.detach();
        mTileProvider.clearTileCache();
        this.mTileProvider=base;
        mTileProvider.setTileRequestCompleteHandler(mTileRequestCompleteHandler);
        updateTileSizeForDensity(mTileProvider.getTileSource());

        this.mMapOverlay = new TilesOverlay(mTileProvider, this.getContext());

        mOverlayManager.setTilesOverlay(mMapOverlay);
        invalidate();
    }

    /**
     * @since 6.0.0
     */
    @Deprecated
    public void setInitCenter(final IGeoPoint geoPoint) {
        setCenter(geoPoint);
    }

    public long getMapScrollX() {
        return mMapScrollX;
    }

    public long getMapScrollY() {
        return mMapScrollY;
    }

    private void setMapScroll(final long pMapScrollX, final long pMapScrollY) {
        mMapScrollX = pMapScrollX;
        mMapScrollY = pMapScrollY;
        requestLayout();
    }

    /**
     * @since 5.6.6
     */
    public GeoPoint getCenter() {
        return mCenter;
    }

    /**
     * @since 5.6.6
     */
    public void setCenter(final IGeoPoint pGeoPoint) {
        mCenter = (GeoPoint)pGeoPoint;
        setMapScroll(0, 0);
        resetProjection();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值