2013-07-25 7 views
2

Как добавить шкалу масштаба на карте, когда значение масштабирования и уменьшения масштаба должно измениться (шкала), и получил отображение органов управления зумом в нижнем правом углу, но я хочу заменить его чуть выше.Как показать шкалу масштаба и масштабирование на карте?

Как это сделать?

Спасибо

ответ

2

Просто добавьте этот код ..

googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL); 
    googleMap.getUiSettings().setZoomControlsEnabled(true); 
    googleMap.getUiSettings().setCompassEnabled(true); 
    googleMap.getUiSettings().setMyLocationButtonEnabled(true); 
    googleMap.getUiSettings().setAllGesturesEnabled(true); 
    googleMap.setMyLocationEnabled(true); 
9

В API нет никакого способа, чтобы установить шкалу масштаба. В этом случае вы должны реализовать его самостоятельно. Это простой пример того, как вы можете это сделать. Я применил код из ответа How to add a map scale in MapView on Android? для работы с GoogleMap.

class ScaleBar extends ImageView { 
    float mXOffset = 10; 
    float mYOffset = 10; 
    float mLineWidth = 3; 
    int mTextSize = 25; 

    boolean mIsImperial = false; 
    boolean mIsNautical = false; 

    boolean mIsLatitudeBar = true; 
    boolean mIsLongitudeBar = true; 

    private GoogleMap mMap; 

    float mXdpi; 
    float mYdpi; 

    public ScaleBar(Context context, GoogleMap map) { 
     super(context); 

     mMap = map; 

     mXdpi = context.getResources().getDisplayMetrics().xdpi; 
     mYdpi = context.getResources().getDisplayMetrics().ydpi; 
    } 

    @Override 
    public void onDraw(Canvas canvas) { 
     canvas.save(); 

     drawScaleBarPicture(canvas); 

     canvas.restore(); 
    } 

    private void drawScaleBarPicture(Canvas canvas) { 
     // 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 = mMap.getProjection(); 

     if (projection == null) { 
      return; 
     } 

     final Paint barPaint = new Paint(); 
     barPaint.setColor(Color.BLACK); 
     barPaint.setAntiAlias(true); 
     barPaint.setStrokeWidth(mLineWidth); 

     final Paint textPaint = new Paint(); 
     textPaint.setColor(Color.BLACK); 
     textPaint.setAntiAlias(true); 
     textPaint.setTextSize(mTextSize); 

     drawXMetric(canvas, textPaint, barPaint); 

     drawYMetric(canvas, textPaint, barPaint); 
    } 

    private void drawXMetric(Canvas canvas, Paint textPaint, Paint barPaint) { 
     Projection projection = mMap.getProjection(); 

     if (projection != null) { 
      LatLng p1 = projection.fromScreenLocation(new Point((int) ((getWidth()/2) - (mXdpi/2)), getHeight()/2)); 
      LatLng p2 = projection.fromScreenLocation(new Point((int) ((getWidth()/2) + (mXdpi/2)), getHeight()/2)); 

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

      locationP1.setLatitude(p1.latitude); 
      locationP2.setLatitude(p2.latitude); 
      locationP1.setLongitude(p1.longitude); 
      locationP2.setLongitude(p2.longitude); 

      float xMetersPerInch = locationP1.distanceTo(locationP2); 

      if (mIsLatitudeBar) { 
       String xMsg = scaleBarLengthText(xMetersPerInch, mIsImperial, mIsNautical); 
       Rect xTextRect = new Rect(); 
       textPaint.getTextBounds(xMsg, 0, xMsg.length(), xTextRect); 

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

       canvas.drawRect(mXOffset, mYOffset, mXOffset + mXdpi, mYOffset + mLineWidth, barPaint); 
       canvas.drawRect(mXOffset + mXdpi, mYOffset, mXOffset + mXdpi + mLineWidth, mYOffset + 
         xTextRect.height() + mLineWidth + textSpacing, barPaint); 

       if (!mIsLongitudeBar) { 
        canvas.drawRect(mXOffset, mYOffset, mXOffset + mLineWidth, mYOffset + 
          xTextRect.height() + mLineWidth + textSpacing, barPaint); 
       } 
       canvas.drawText(xMsg, (mXOffset + mXdpi/2 - xTextRect.width()/2), 
         (mYOffset + xTextRect.height() + mLineWidth + textSpacing), textPaint); 
      } 
     } 
    } 

    private void drawYMetric(Canvas canvas, Paint textPaint, Paint barPaint) { 
     Projection projection = mMap.getProjection(); 

     if (projection != null) { 
      Location locationP1 = new Location("ScaleBar location p1"); 
      Location locationP2 = new Location("ScaleBar location p2"); 

      LatLng p1 = projection.fromScreenLocation(new Point(getWidth()/2, 
        (int) ((getHeight()/2) - (mYdpi/2)))); 
      LatLng p2 = projection.fromScreenLocation(new Point(getWidth()/2, 
        (int) ((getHeight()/2) + (mYdpi/2)))); 

      locationP1.setLatitude(p1.latitude); 
      locationP2.setLatitude(p2.latitude); 
      locationP1.setLongitude(p1.longitude); 
      locationP2.setLongitude(p2.longitude); 

      float yMetersPerInch = locationP1.distanceTo(locationP2); 

      if (mIsLongitudeBar) { 
       String yMsg = scaleBarLengthText(yMetersPerInch, mIsImperial, mIsNautical); 
       Rect yTextRect = new Rect(); 
       textPaint.getTextBounds(yMsg, 0, yMsg.length(), yTextRect); 

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

       canvas.drawRect(mXOffset, mYOffset, mXOffset + mLineWidth, mYOffset + mYdpi, barPaint); 
       canvas.drawRect(mXOffset, mYOffset + mYdpi, mXOffset + yTextRect.height() + 
         mLineWidth + textSpacing, mYOffset + mYdpi + mLineWidth, barPaint); 

       if (!mIsLatitudeBar) { 
        canvas.drawRect(mXOffset, mYOffset, mXOffset + yTextRect.height() + 
          mLineWidth + textSpacing, mYOffset + mLineWidth, barPaint); 
       } 

       float x = mXOffset + yTextRect.height() + mLineWidth + textSpacing; 
       float y = mYOffset + mYdpi/2 + yTextRect.width()/2; 

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

    private String scaleBarLengthText(float meters, boolean imperial, boolean nautical) { 
     if (this.mIsImperial) { 
      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.mIsNautical) { 
      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"; 
      } 
     } 
    } 
} 

Затем вы можете добавить это в свой макет таким образом:

RelativeLayout container = (RelativeLayout) findViewById(R.id.main_view); 
    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(800, 800); 

    params.addRule(RelativeLayout.CENTER_HORIZONTAL); 
    params.addRule(RelativeLayout.CENTER_VERTICAL); 

    mScaleBar = new ScaleBar(this, mMap); 
    mScaleBar.setLayoutParams(params); 

Надеется, что это будет полезно для кого-то.

+2

отлично работает. просто нужно добавить обработчик onTouch, и добавить mScaleBar.invalidate() – dariusiv

+0

@dariusiv в конструктор класса вы можете добавить следующий код недействительным вид: 'mMap.setOnCameraMoveListener (новый GoogleMap.OnCameraMoveListener() { @ Override public void onCameraMove() { invalidate(); } }); ' – ClarkXP

0

Как уже говорилось, в API Карт Google нет упоминания о шкале масштаба. Нужно программировать их самостоятельно. Я взял ответ от Arkadiusz Cieśliński и расширил его, чтобы получить более масштабный вид Google Maps.

import android.content.Context; 
import android.graphics.Canvas; 
import android.graphics.Paint; 
import android.graphics.Path; 
import android.graphics.Point; 
import android.graphics.PointF; 
import android.graphics.Rect; 
import android.location.Location; 
import android.support.v7.widget.AppCompatImageView; 
import android.util.AttributeSet; 

import com.google.android.gms.maps.GoogleMap; 
import com.google.android.gms.maps.Projection; 
import com.google.android.gms.maps.model.LatLng; 

import java.util.Locale; 

import thermcam.georg.locationhistoryviewer.R; 
import thermcam.georg.locationhistoryviewer.util.ResourcesUtil; 

/** 
* Created by georg on 18.04.17. 
*/ 

public class MapScaleBar extends AppCompatImageView{ 

    public enum ColorMode { 
     COLOR_MODE_AUTO, 
     COLOR_MODE_DARK, 
     COLOR_MODE_WHITE 
    } 

    private static final int FT_IN_MILE = 5280; 

    private static final int[] METERS = {1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 
      10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000}; 

    private static final int[] FT = {1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 
      FT_IN_MILE, 2 * FT_IN_MILE, 5 * FT_IN_MILE, 10 * FT_IN_MILE, 20 * FT_IN_MILE, 50 * FT_IN_MILE, 
      100 * FT_IN_MILE, 200 * FT_IN_MILE, 500 * FT_IN_MILE, 1000 * FT_IN_MILE, 2000 * FT_IN_MILE}; 

    float mXOffset = 10; // in px 
    float mYOffset = 10; // in px 
    private float mLineWidth = 4; // in dp 
    private float mTextSize = 15; // in dp 
    private float mTextPadding = 2; // in dp 

    public ColorMode mColorMode = ColorMode.COLOR_MODE_AUTO; 

    private GoogleMap mMap; 

    float mXdpi; 
    float mYdpi; 

    public MapScaleBar(Context context) { 
     this(context, null); 
    } 

    public MapScaleBar(Context context, AttributeSet attrs) { 
     this(context, attrs, 0); 
    } 

    public MapScaleBar(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 

     mXdpi = context.getResources().getDisplayMetrics().xdpi; 
     mYdpi = context.getResources().getDisplayMetrics().ydpi; 

     setLineWidth(mLineWidth); 
     setTextSize(mTextSize); 
     setTextPadding(mTextPadding); 
    } 

    public void addTarget(GoogleMap map) { 
     this.mMap = map; 

     map.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() { 
      @Override 
      public void onCameraMove() { 
       invalidate(); 
      } 
     }); 
    } 

    public void setLineWidth(float lineWidth) { 
     this.mLineWidth = pxToDp(lineWidth); 
    } 

    public void setTextSize(float textSize) { 
     this.mTextSize = pxToDp(textSize); 
    } 

    public void setTextPadding(float textPadding) { 
     this.mTextPadding = pxToDp(textPadding); 
    } 

    public float pxToDp(float px) { 
     return px * (mYdpi/160); 
    } 

    @Override 
    public void onDraw(Canvas canvas) { 
     if (mMap == null) 
      return; 

     canvas.save(); 

     drawScaleBarPicture(canvas); 

     canvas.restore(); 
    } 

    private void drawScaleBarPicture(Canvas canvas) { 
     // 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. 

     int darkC = ResourcesUtil.getColor(getResources(), R.color.textDarkPrimary, null); 
     int whiteC = ResourcesUtil.getColor(getResources(), R.color.textLightPrimary, null); 

     if (mColorMode == ColorMode.COLOR_MODE_WHITE || 
       mColorMode == ColorMode.COLOR_MODE_AUTO && (mMap.getMapType() == GoogleMap.MAP_TYPE_SATELLITE || mMap.getMapType() == GoogleMap.MAP_TYPE_HYBRID)) 
      drawXMetric(canvas, whiteC, darkC); 
     else 
      drawXMetric(canvas, darkC, whiteC); 
    } 

    private void drawXMetric(Canvas canvas, int fillColor, int outlineColor) { 
     Projection projection = mMap.getProjection(); 

     LatLng p1 = projection.fromScreenLocation(new Point(
       (int) ((getWidth()/2) - (mXdpi/2)), getHeight()/2)); 
     LatLng p2 = projection.fromScreenLocation(new Point((int) (
       (getWidth()/2) + (mXdpi/2)), getHeight()/2)); 

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

     locationP1.setLatitude(p1.latitude); 
     locationP2.setLatitude(p2.latitude); 
     locationP1.setLongitude(p1.longitude); 
     locationP2.setLongitude(p2.longitude); 


     // PAINTS 
     final Paint barPaintFill = new Paint(Paint.ANTI_ALIAS_FLAG); 
     barPaintFill.setStyle(Paint.Style.FILL); 
     barPaintFill.setColor(fillColor); 

     final Paint barPaintStroke = new Paint(barPaintFill); 
     barPaintStroke.setColor(outlineColor); 
     barPaintStroke.setStyle(Paint.Style.STROKE); 
     barPaintStroke.setStrokeWidth(mLineWidth/5); 

     final Paint textPaintFill = new Paint(barPaintFill); 
     textPaintFill.setTextSize(mTextSize); 

     final Paint textPaintStroke = new Paint(barPaintStroke); 
     textPaintStroke.setTextSize(mTextSize); 

     // LENGTH 
     float xMetersPerInch = locationP1.distanceTo(locationP2); 

     int nearestM = findNextSmallestInUnit(xMetersPerInch, false); 
     int nearestFT = findNextSmallestInUnit(xMetersPerInch, true); 
     float lengthM = mXdpi/xMetersPerInch * nearestM; 
     float lengthFT = mXdpi/xMetersPerInch * (nearestFT/3.2808f); 
     String msgM = scaleBarLengthText(nearestM, false); 
     String msgFT = scaleBarLengthText(nearestFT, true); 

     float longest = Math.max(lengthFT, lengthM); 

     // Get text rects & cords 
     Rect textRectM = new Rect(); 
     textPaintFill.getTextBounds(msgM, 0, msgM.length(), textRectM); 
     Rect textRectFT = new Rect(); 
     textPaintFill.getTextBounds(msgFT, 0, msgFT.length(), textRectFT); 

     PointF textCoordM = new PointF(canvas.getWidth() - mXOffset - textRectM.width() - mTextPadding, 
       canvas.getHeight() - mYOffset - textRectFT.height() - mTextPadding * 2 - mLineWidth); 
     PointF textCoordFT = new PointF(canvas.getWidth() - mXOffset - textRectFT.width() - mTextPadding, 
       canvas.getHeight() - mYOffset - textRectFT.height() - textRectFT.top); 
     // PointF textCoordFT = new PointF() 

     // All movements are based in the bottom, right corner 
     Path barP = new Path(); 
     barP.setFillType(Path.FillType.EVEN_ODD); 
     barP.moveTo(canvas.getWidth() - mXOffset, canvas.getHeight() - mYOffset - textRectFT.height() - mTextPadding); 

     barP.rLineTo(- lengthFT + mLineWidth, 0); 
     barP.rLineTo(0, textRectFT.height() * 0.6f); 
     barP.rLineTo(- mLineWidth, 0); 
     barP.rLineTo(0, -textRectFT.height() * 0.6f); 
     barP.rLineTo(lengthFT - longest, 0); 
     barP.rLineTo(0, - mLineWidth); 
     barP.rLineTo(longest - lengthM, 0); 
     barP.rLineTo(0, -textRectM.height() * 0.6f); 
     barP.rLineTo(mLineWidth, 0); 
     barP.rLineTo(0, textRectM.height() * 0.6f); 
     barP.rLineTo(lengthM - mLineWidth, 0); 
     barP.close(); 

     canvas.drawPath(barP, barPaintFill); 
     canvas.drawPath(barP, barPaintStroke); 

     canvas.drawText(msgM, textCoordM.x, textCoordM.y, textPaintStroke); 
     canvas.drawText(msgM, textCoordM.x, textCoordM.y, textPaintFill); 

     canvas.drawText(msgFT, textCoordFT.x, textCoordFT.y, textPaintStroke); 
     canvas.drawText(msgFT, textCoordFT.x, textCoordFT.y, textPaintFill); 
    } 

    private int findNextSmallestInUnit(float meters, boolean imperial) { 
     int[] data = imperial ? FT : METERS; 
     float value = meters * (imperial ? 3.2808f : 1); 

     int closest = data[0]; 

     for (int elem: data) { 
      if (elem - value > 0) 
       break; 
      else 
       closest = elem; 
     } 

     return closest; 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     setMeasuredDimension((int)mXdpi, (int)(mTextPadding * 4 + mTextSize * 2 + mLineWidth)); 
    } 

    private String scaleBarLengthText(int value, boolean imperial) { 
     if (imperial) { 
      if (value >= FT_IN_MILE) 
       return String.format(Locale.getDefault(), "%d mi", value/FT_IN_MILE); 
      else 
       return String.format(Locale.getDefault(), "%d ft", value); 
     } else { 
      if (value >= 1000) 
       return String.format(Locale.getDefault(), "%d km", value/1000); 
      else 
       return String.format(Locale.getDefault(), "%d m", value); 
     } 
    } 
} 

А может его использовать, добавив его в свой layout.xml. Например, как это:

<package.id.MapScaleBar 
    android:id="@+id/scaleBar" 
    android:layout_centerInParent="true" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" /> 

Вы тогда просто нужно добавить экземпляр Google Map в addTarget методе его, например, в onMapReady(GoogleMap googleMap) функции.

MapScaleBar scaleBar = (MapScaleBar)findViewById(R.id.scaleBar); 
scaleBar.mColorMode = MapScaleBar.ColorMode.COLOR_MODE_DARK; // normal 
scaleBar.mColorMode = MapScaleBar.ColorMode.COLOR_MODE_WHITE; // inverted 
scaleBar.mColorMode = MapScaleBar.ColorMode.COLOR_MODE_AUTO; // detect automatically after Google Map style 
scaleBar.addTarget(mMap); 
1

Я создал небольшую библиотеку на основе предыдущих ответов.
https://github.com/pengrad/MapScaleView

Добавить зависимость

compile 'com.github.pengrad:mapscaleview:1.2.0'

Включить в макете над Карта

<FrameLayout 
xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:app="http://schemas.android.com/apk/res-auto" 
android:id="@+id/activity_main" 
android:layout_width="match_parent" 
android:layout_height="match_parent"> 

    <fragment 
     android:id="@+id/mapFragment" 
     class="com.google.android.gms.maps.SupportMapFragment" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"/> 

    <com.github.pengrad.mapscaleview.MapScaleView 
     android:id="@+id/scaleView" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="bottom|end" 
     android:layout_margin="4dp"/> 
</FrameLayout> 

Обновление в коде

MapScaleView scaleView = (MapScaleView) findViewById(R.id.scaleView); 
CameraPosition cameraPosition = map.getCameraPosition(); 
// need to pass zoom and latitude 
scaleView.update(cameraPosition.zoom, cameraPosition.target.latitude);