当前位置: 首页 > 面试题库 >

如何在Android的MapView中添加地图比例尺?

耿星雨
2023-03-14
问题内容

我正在努力添加一个地图比例尺,该比例尺根据当前缩放级别在屏幕上显示当前长度。我感觉它可能存在一些预定义的类可以使用,但是我不知道…?我搜索了很多东西,但找不到任何东西。

我非常感谢的任何帮助=)

//亚历克斯


问题答案:

好吧,我明白了!Luis的回答对我和OpenStreetMap都有帮助。这是我想出的:

<your.own.package.path>;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Picture;
import android.graphics.Rect;
import android.location.Location;
import android.util.Log;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
import com.iqqn.uppgift5.GameMapActivity;

public class ScaleBarOverlay extends Overlay{

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

    // Defaults

    boolean enabled = true;

    float xOffset = 10;
    float yOffset = 10;
    float lineWidth = 2;
    int textSize = 12;

    boolean imperial = false;
    boolean nautical = false;

    boolean latitudeBar = true;
    boolean longitudeBar = false;

    // Internal

    protected final MapView mapView;
    protected final GameMapActivity master;

    private Context context;

    protected final Picture scaleBarPicture = new Picture();
    private final Matrix scaleBarMatrix = new Matrix();

    private int lastZoomLevel = -1;

    float xdpi;
    float ydpi;
    int screenWidth;
    int screenHeight;

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

    public ScaleBarOverlay(Context _context, GameMapActivity master, MapView mapView) {
        super();

        this.master = master;
        this.context = _context;
        this.mapView = mapView;

        xdpi = this.context.getResources().getDisplayMetrics().xdpi;
        ydpi = this.context.getResources().getDisplayMetrics().ydpi;

        screenWidth = this.context.getResources().getDisplayMetrics().widthPixels;
        screenHeight = this.context.getResources().getDisplayMetrics().heightPixels;

    }

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

    /**
     * @return the enabled
     */
    public boolean isEnabled() {
        return enabled;
    }

    /**
     * @param enabled the enabled to set
     */
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    /**
     * @return the lineWidth
     */
    public float getLineWidth() {
        return lineWidth;
    }

    /**
     * @param lineWidth the lineWidth to set
     */
    public void setLineWidth(float lineWidth) {
        this.lineWidth = lineWidth;
    }

    /**
     * @return the imperial
     */
    public boolean isImperial() {
        return imperial;
    }

    /**
     * @param imperial the imperial to set
     */
    public void setImperial() {
        this.imperial = true;
        this.nautical = false;
        createScaleBarPicture();
    }

    /**
     * @return the nautical
     */
    public boolean isNautical() {
        return nautical;
    }

    /**
     * @param nautical the nautical to set
     */
    public void setNautical() {
        this.nautical = true;
        this.imperial = false;
        createScaleBarPicture();
    }

    public void setMetric() {
        this.nautical = false;
        this.imperial = false;
        createScaleBarPicture();
    }

    public void drawLatitudeScale(boolean latitude) {
        this.latitudeBar = latitude;
    }

    public void drawLongitudeScale(boolean longitude) {
        this.longitudeBar = longitude;
    }

    @Override
    public void draw(Canvas canvas, MapView localMapView, boolean shadow) {
        if (this.enabled) {
            // Draw the overlay
            if (shadow == false) {
                final int zoomLevel = localMapView.getZoomLevel();

                if (zoomLevel != lastZoomLevel) {
                    lastZoomLevel = zoomLevel;
                    createScaleBarPicture();
                }

                this.scaleBarMatrix.setTranslate(-1 * (scaleBarPicture.getWidth() / 2 - 0.5f), -1 * (scaleBarPicture.getHeight() / 2 - 0.5f));
                this.scaleBarMatrix.postTranslate(xdpi/2, ydpi/2 + canvas.getHeight()-50);

                canvas.save();
                canvas.setMatrix(scaleBarMatrix);
                canvas.drawPicture(scaleBarPicture);
                canvas.restore();
            }
        }
    }

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

    public void disableScaleBar() {
        this.enabled = false;
    }

    public boolean enableScaleBar() {
        return this.enabled = true;
    }

    private void createScaleBarPicture() {
        // We want the scale bar to be as long as the closest round-number miles/kilometers
        // to 1-inch at the latitude at the current center of the screen.

        Projection projection = mapView.getProjection();

        if (projection == null) {
            return;
        }

        Location locationP1 = new Location("ScaleBar location p1");
        Location locationP2 = new Location("ScaleBar location p2");

        // Two points, 1-inch apart in x/latitude, centered on screen
        GeoPoint p1 = projection.fromPixels((int) ((screenWidth / 2) - (xdpi / 2)), screenHeight/2);
        GeoPoint p2 = projection.fromPixels((int) ((screenWidth / 2) + (xdpi / 2)), screenHeight/2);

        locationP1.setLatitude(p1.getLatitudeE6()/1E6);
        locationP2.setLatitude(p2.getLatitudeE6()/1E6);
        locationP1.setLongitude(p1.getLongitudeE6()/1E6);
        locationP2.setLongitude(p2.getLongitudeE6()/1E6);

        float xMetersPerInch = locationP1.distanceTo(locationP2);

        p1 = projection.fromPixels(screenWidth/2, (int) ((screenHeight / 2) - (ydpi / 2)));
        p2 = projection.fromPixels(screenWidth/2, (int) ((screenHeight / 2) + (ydpi / 2)));

        locationP1.setLatitude(p1.getLatitudeE6()/1E6);
        locationP2.setLatitude(p2.getLatitudeE6()/1E6);
        locationP1.setLongitude(p1.getLongitudeE6()/1E6);
        locationP2.setLongitude(p2.getLongitudeE6()/1E6);

        float yMetersPerInch =  locationP1.distanceTo(locationP2);

        final Paint barPaint = new Paint();
        barPaint.setColor(Color.BLACK);
        barPaint.setAntiAlias(true);
        barPaint.setStyle(Style.FILL);
        barPaint.setAlpha(255);

        final Paint textPaint = new Paint();
        textPaint.setColor(Color.BLACK);
        textPaint.setAntiAlias(true);
        textPaint.setStyle(Style.FILL);
        textPaint.setAlpha(255);
        textPaint.setTextSize(textSize);

        final Canvas canvas = scaleBarPicture.beginRecording((int)xdpi, (int)ydpi);

        if (latitudeBar) {
            String xMsg = scaleBarLengthText(xMetersPerInch, imperial, nautical);
            Rect xTextRect = new Rect();
            textPaint.getTextBounds(xMsg, 0, xMsg.length(), xTextRect);

            int textSpacing = (int)(xTextRect.height() / 5.0);

            canvas.drawRect(xOffset, yOffset, xOffset + xdpi, yOffset + lineWidth, barPaint);
            canvas.drawRect(xOffset + xdpi, yOffset, xOffset + xdpi + lineWidth, yOffset + xTextRect.height() + lineWidth + textSpacing, barPaint);

            if (!longitudeBar) {
                canvas.drawRect(xOffset, yOffset, xOffset + lineWidth, yOffset + xTextRect.height() + lineWidth + textSpacing, barPaint);
            }
            canvas.drawText(xMsg, (xOffset + xdpi/2 - xTextRect.width()/2), (yOffset + xTextRect.height() + lineWidth + textSpacing), textPaint);
        }

        if (longitudeBar) {
            String yMsg = scaleBarLengthText(yMetersPerInch, imperial, nautical);
            Rect yTextRect = new Rect();
            textPaint.getTextBounds(yMsg, 0, yMsg.length(), yTextRect);

            int textSpacing = (int)(yTextRect.height() / 5.0);

            canvas.drawRect(xOffset, yOffset, xOffset + lineWidth, yOffset + ydpi, barPaint);
            canvas.drawRect(xOffset, yOffset + ydpi, xOffset + yTextRect.height() + lineWidth + textSpacing, yOffset + ydpi + lineWidth, barPaint);

            if (! latitudeBar) {
                canvas.drawRect(xOffset, yOffset, xOffset + yTextRect.height() + lineWidth + textSpacing, yOffset + lineWidth, barPaint);
            }

            float x = xOffset + yTextRect.height() + lineWidth + textSpacing;
            float y = yOffset + ydpi/2 + yTextRect.width()/2;

            canvas.rotate(-90, x, y);
            canvas.drawText(yMsg, x, y + textSpacing, textPaint);

        }

        scaleBarPicture.endRecording();
    }

    private String scaleBarLengthText(float meters, boolean imperial, boolean nautical) {
        if (this.imperial) {
            if (meters >= 1609.344) {
                return (meters / 1609.344) + "mi";
            } else if (meters >= 1609.344/10) {
                return ((meters / 160.9344) / 10.0) + "mi";
            } else {
                return (meters * 3.2808399) + "ft";
            }
        } else if (this.nautical) {
            if (meters >= 1852) {
                return ((meters / 1852)) + "nm";
            } else if (meters >= 1852/10) {
                return (((meters / 185.2)) / 10.0) + "nm";
            } else {
                return ((meters * 3.2808399)) + "ft";
            }
        } else {
            if (meters >= 1000) {
                return ((meters / 1000)) + "km";
            } else if (meters > 100) {
                return ((meters / 100.0) / 10.0) + "km";
            } else {
                return meters + "m";
            }
        }
    }

    @Override
    public boolean onTap(GeoPoint point, MapView mapView) {
        // Do not react to screen taps.
        return false;
    }
}

在onCreate()中以以下方式使用它:

...
scaleBarOverlay = new ScaleBarOverlay(this.getBaseContext(), this, myMapView);
List<Overlay> overlays = myMapView.getOverlays();
// Add scale bar overlay
scaleBarOverlay.setMetric();
overlays.add(scaleBarOverlay);
...

希望这对任何人都有帮助=)这将在API级别7+上起作用。我尚未在API级别14+上对其进行测试,并且我知道一些硬件加速的东西“不”在那里工作,例如使用画布绘制图片。但我认为它将与录音一起使用。

再次感谢路易斯!

//亚历山大



 类似资料:
  • 问题内容: 我在用 在或中,如果我们向其添加标签,则可以轻松放置图例。但是如果是或 我知道有一个可以显示颜色范围的颜色,但是并不满意。我想要一个带有名称(标签)的 我能想到的是,向矩阵中的每个元素添加标签,然后,尝试legend(),以查看其是否有效,但是如何向元素添加标签(如值)? 就我而言,原始数据如下: 例如,1代表“草”,2代表“沙”,3代表“山” …依此类推。imshow()非常适合我的

  • 问题内容: 这段代码返回:8或10或6作为循环后映射的长度。视频在这里, 游戏 在这里。 我看到新添加的元素进入范围,但无法解释为什么此循环随机停止吗? 问题答案: 规格:对于声明: 未指定地图的迭代顺序,并且不能保证每次迭代之间都相同。如果在迭代过程中删除了尚未到达的映射条目,则不会生成相应的迭代值。 如果在迭代过程中创建了映射条目,则该条目可能在迭代过程中产生或可以被跳过。 对于创建的每个条目

  • 问题内容: 应用崩溃时,我收到如下错误日志: 致命异常:com.facebook.react.modules.core.JavascriptException:onSelect index.android.bundle:20:7148 onPress index.android.bundle:20:2435 但这对我排除麻烦不是真的有帮助。如何启用源地图,以便能够找出问题所在? UPDATE 20

  • 我正在尝试创建如何使用MapView获取。我创建了一个片段和一个XML来使用它。问题是,当我尝试打开MapView时,它会抛出NullPointerException,但我无法理解为什么。 我该怎么解决呢? XML 碎片 例外

  • 对于一个项目,我正在创建不同的层,这些层都应该被写入一个geopackage。我正在使用QGIS 3.16.1和运行在Python 3.7上的QGIS中的Python控制台 我尝试了很多事情,但不知道如何做到这一点。这是我目前使用的。 问题是,在“测试”中。“gpkg”创建的层称为“测试”,而不是“点1”或“点2”。和第二个QgsVectorFileWriter。writeAsVectorForm