Android 自定义高德地图比例尺

xiaoxiao2021-02-28  58

高德地图有提供自带的比例尺,但是不能改变位置,只能固定在屏幕右下角,做项目时,有些需求非要在某个位置,那就只能自定义了。

用高德自带的比例尺测试过,同一缩放等级,不同经纬度,比例尺也可能是不一样的,所以不能根据缩放等级处理。

好在高德地图有提供相应api

比例尺数据:AMap. getScalePerPixel()可以获取当前地图级别下1像素点对应的距离长度(米),然后可自定义比例尺长度(如100像素)。

效果图如下。

完整代码: import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.View; import com.amap.api.maps.AMap; import com.autonavi.amap.mapcore.DPoint; import com.autonavi.amap.mapcore.IPoint; import com.autonavi.amap.mapcore.VirtualEarthProjection; /** * @author gcz * blog https://blog.csdn.net/z19980115/article/details/78795329 */ public final class MapScaleView extends View { private static final float a = 0.9F; //最大宽度,超过该宽度就向下一级转换 private static final int maxWidth = 150; //比例尺文本 private String text = ""; //比例尺宽度 private int lineWidth = 50; //视图高度 private int viewHeight; //比例尺线条画笔 private Paint linePaint; //比例尺文本画笔 private Paint textPaint; //文本的区域 private Rect rect; private IPoint point; //1dp转px后的值 private float dp1 = 0.0F; private final int[] level = new int[]{10000000, 5000000, 2000000, 1000000, 500000, 200000, 100000, 50000, 30000, 20000, 10000, 5000, 2000, 1000, 500, 200, 100, 50, 25, 10, 5}; public MapScaleView(Context context) { this(context, null); } public MapScaleView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public MapScaleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { this.rect = new Rect(0, 0, 0, 10); this.linePaint = new Paint(); this.linePaint.setAntiAlias(true); this.linePaint.setColor(Color.WHITE); this.linePaint.setStrokeWidth(2.0F * a); this.linePaint.setStyle(Paint.Style.STROKE); this.textPaint = new Paint(); this.textPaint.setAntiAlias(true); this.textPaint.setColor(Color.WHITE); this.textPaint.setTextSize(20.0F * a); this.dp1 = (float) getDp1(context); this.point = new IPoint(); } public void destroy() { this.linePaint = null; this.textPaint = null; this.rect = null; this.text = null; this.point = null; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (this.text != null && !this.text.equals("") && this.lineWidth != 0) { this.textPaint.getTextBounds(this.text, 0, this.text.length(), this.rect); int x = 1; int y = viewHeight - this.rect.height() + 5; canvas.drawText(this.text, (this.lineWidth - this.rect.width()) / 2, y, this.textPaint); y += this.rect.height() - 5; //左竖线 canvas.drawLine(x, y - 3.0F * this.dp1, x, y + a, this.linePaint); //横线 canvas.drawLine(x, y - x, this.lineWidth, y - x, this.linePaint); //右竖线 canvas.drawLine(this.lineWidth, y - 3.0F * this.dp1, this.lineWidth, y + a, this.linePaint); } } public void refreshScaleView(AMap aMap) { if (aMap == null) return; try { float zoom = aMap.getCameraPosition().zoom; //获取地图中心坐标 aMap.getP20MapCenter(this.point); if (this.point != null) { DPoint dPoint = VirtualEarthProjection.PixelsToLatLong((long) this.point.x, (long) this.point.y, 20); float var3 = 1; //屏幕上1像素点对应的地图上距离长度,单位米,等同于aMap.getScalePerPixel(); double scalePerPixel = (double) ((float) (Math.cos(dPoint.y * 3.141592653589793D / 180.0D) * 2.0D * 3.141592653589793D * 6378137.0D / (256.0D * Math.pow(2.0D, (double) zoom)))); //比例尺宽度 int lineWidth = (int) ((double) this.level[(int) zoom] / (scalePerPixel * (double) var3)); String lineText = formatDistance(this.level[(int) zoom]); //如果超过最大宽度,则向下一级转换 while (lineWidth > maxWidth && zoom < 19) { zoom++; lineWidth = (int) ((double) this.level[(int) zoom] / (scalePerPixel * (double) var3)); lineText = formatDistance(this.level[(int) zoom]); } this.lineWidth = lineWidth; this.text = lineText; dPoint.recycle(); this.requestLayout(); this.invalidate(); } } catch (Throwable throwable) { throwable.printStackTrace(); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthSize = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); int resultWidth; if (widthMode == MeasureSpec.EXACTLY) {//精确模式,写死宽度的情况 resultWidth = widthSize; } else { resultWidth = Math.max(lineWidth, rect.width()) + 2; if (widthMode == MeasureSpec.AT_MOST) {//最大模式,父容器给的最大空间 resultWidth = Math.min(resultWidth, widthSize); } } int heightSize = getHeightSize(heightMeasureSpec); viewHeight = heightSize; setMeasuredDimension(resultWidth, heightSize); } /** * 测量ScaleView的高度 */ private int getHeightSize(int heightMeasureSpec) { int mode = MeasureSpec.getMode(heightMeasureSpec); int height = 0; switch (mode) { case MeasureSpec.AT_MOST: height = (int) (rect.height() + 5 + 3F * this.dp1 + a); break; case MeasureSpec.EXACTLY: { height = MeasureSpec.getSize(heightMeasureSpec); break; } case MeasureSpec.UNSPECIFIED: { height = Math.max((int) (rect.height() + 5 + 3F * this.dp1 + a), MeasureSpec.getSize(heightMeasureSpec)); break; } } return height; } public static String formatDistance(int m) { String distance; if (m < 1000) { distance = m + "m"; } else { distance = m / 1000 + "km"; } return distance; } /** * 1dp转px */ public static int getDp1(Context var0) { float var1 = var0.getResources().getDisplayMetrics().density; return (int) (1.0F * var1 + 0.5F); } } 使用方法: 和正常view一样添加到layout中,注意 修改包名 <com.xxx.xxx.MapScaleView android:id="@+id/blc" android:layout_width="wrap_content" android:layout_height="wrap_content" />

在OnCameraChangeListener的onCameraChange中调用比例尺的refreshScaleView()

override fun onCameraChange(p0: CameraPosition?) { if (p0 == null) return blc.refreshScaleView(mMap) }

参考资料: 如何自定义指南针、缩放按钮、比例尺控件、定位按钮? ArcGIS for Android 自定义地图比例尺

转载请注明原文地址: https://www.6miu.com/read-1600466.html

最新回复(0)