2012-10-18 55 views
2

我正在努力添加一個地圖比例,根據當前縮放級別在屏幕上顯示當前長度。我有一種感覺,它可能存在一些預定義的類,但我不知道......?我搜遍了很多,但找不到任何東西。如何在Android上的MapView中添加地圖比例尺?

任何幫助,我非常感謝=)

//亞歷

回答

6

好吧,我明白了!路易斯的回答幫了我很多,也是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+上測試過它,而且我知道某些硬件加速的東西「不」在那裏工作,如使用畫布繪製圖片。但我認爲它會與錄音一起工作。

再次感謝路易斯!

//亞歷山大

+0

要讓代碼適用於您自己的實現,只需從'ScaleBarOverlay'中刪除'GameMapActivity master',並且您已完全工作和可用的類爲您自己的實現! –

+0

不客氣。 – Luis

+0

您的代碼中存在一個錯誤。您需要在每次更換相機時刷新比例尺,而不僅僅是縮放更改(比例尺長度也取決於緯度)。 – zyamys

3

據我所知,沒有一個predifined類來做到這一點。

一種可能性是創建覆蓋圖,該覆蓋圖檢查當前經度跨度,因爲它隨緯度變化,然後以正確尺寸繪製比例。

波紋管,你可以找到關於如何做到這一點的例子:

比例尺覆蓋

public class CopyOfScaleBarOverlay extends Overlay {  
private static final String STR_M = "m"; 
private static final String STR_KM = "km"; 

//Constants 
private static float scaleBarProportion = 0.25f; 
private float cMarginLeft=4; 
private float cLineTopSize=8; 
private float cMarginTop=6; 
private float cMarginBottom=2; 
private float cTextSize=12; 
private float distanceFromBottom=100; 


//instantiation 
private Context context; 

private Paint paintLine, paintText, paintRectangle; 
private Location l0; 
private Location l1; 
private float ds; 
private int width, height, pi; 
private float marginLeft, marginTop, marginBottom, lineTopSize; 
private String unit; 



public CopyOfScaleBarOverlay(Context context){ 
    super(); 
    this.context=context; 

    paintText= new TextPaint(); 
    paintText.setARGB(180, 0, 0, 0); 
    paintText.setAntiAlias(true); 
    paintText.setTextAlign(Align.CENTER); 

    paintRectangle = new Paint(); 
    paintRectangle.setARGB(80,255,255,255); 
    paintRectangle.setAntiAlias(true); 

    paintLine = new Paint(); 
    paintLine.setARGB(180, 0, 0, 0); 
    paintLine.setAntiAlias(true); 

    l0 = new Location("none"); 
    l1 = new Location("none"); 

    ds=this.context.getApplicationContext().getResources().getDisplayMetrics().density; 
    width=this.context.getApplicationContext().getResources().getDisplayMetrics().widthPixels; 
    height=this.context.getApplicationContext().getResources().getDisplayMetrics().heightPixels; 
    pi = (int) (height - distanceFromBottom *ds); 

    marginLeft=cMarginLeft*ds; 
    lineTopSize=cLineTopSize*ds; 
    marginTop=cMarginTop*ds; 
    marginBottom=cMarginBottom*ds; 


} 

@Override 
public void draw(Canvas canvas, MapView mapview, boolean shadow) { 
    super.draw(canvas, mapview, shadow); 
    if(mapview.getZoomLevel() > 1){ 

     //Calculate scale bar size and units 
     GeoPoint g0 = mapview.getProjection().fromPixels(0, height/2); 
     GeoPoint g1 = mapview.getProjection().fromPixels(width, height/2); 
     l0.setLatitude(g0.getLatitudeE6()/1E6); 
     l0.setLongitude(g0.getLongitudeE6()/1E6); 
     l1.setLatitude(g1.getLatitudeE6()/1E6); 
     l1.setLongitude(g1.getLongitudeE6()/1E6); 
     float d01=l0.distanceTo(l1); 
     float d02=d01*scaleBarProportion; 
     // multiply d02 by a unit conversion factor if needed 
     float cd02; 
     if(d02 > 1000){ 
      unit = STR_KM; 
      cd02 = d02/1000; 
     } else{ 
      unit = STR_M; 
      cd02 = d02; 
     } 
     int i=1; 
     do{ 
      i *=10; 
     }while (i <= cd02); 
     i/=10; 
     float dcd02=(int)(cd02/i)*i; 
     float bs=dcd02*width/d01*d02/cd02; 

     String text=String.format("%.0f %s", dcd02, unit); 
     paintText.setTextSize(cTextSize * ds); 
     float text_x_size=paintText.measureText(text); 
     float x_size = bs + text_x_size/2 + 2*marginLeft; 

     //Draw rectangle 
     canvas.drawRect(0,pi,x_size,pi+marginTop+paintText.getFontSpacing()+marginBottom, paintRectangle); 

     //Draw line 
     canvas.drawLine(marginLeft, pi+marginTop, marginLeft + bs, pi+marginTop, paintLine); 
     //Draw line tops 
     canvas.drawLine(marginLeft, pi+marginTop - lineTopSize/2, marginLeft, pi+marginTop + lineTopSize/2, paintLine); 
     canvas.drawLine(marginLeft +bs, pi+marginTop - lineTopSize/2, marginLeft+bs, pi+marginTop + lineTopSize/2, paintLine); 
     //Draw line midle 
     canvas.drawLine(marginLeft + bs/2, pi+marginTop - lineTopSize/3, marginLeft + bs/2, pi+marginTop + lineTopSize/3, paintLine); 
     //Draw line quarters 
     canvas.drawLine(marginLeft + bs/4, pi+marginTop - lineTopSize/4, marginLeft + bs/4, pi+marginTop + lineTopSize/4, paintLine); 
     canvas.drawLine(marginLeft + 3*bs/4, pi+marginTop - lineTopSize/4, marginLeft + 3*bs/4, pi+marginTop + lineTopSize/4, paintLine); 

     //Draw text 
     canvas.drawText(text, marginLeft +bs, pi+marginTop+paintText.getFontSpacing(), paintText); 
    } 
} 

}

要使用

在您的活動,extendes MapActivity ,添加以下內容:

mapView.getOverlays().add(new CopyOfScaleBarOverlay(this)); 

的例子是使用公制單位。要使用不同的單位制,請將上面代碼中的d02乘以單位換算係數,然後用單位名稱調整字符串。

享受它。

+0

啊,好!像魅力一樣工作!但我看着如何開放街道地圖,並修改了他們的代碼與谷歌地圖工作。我認爲我的方式將盡量減少所需的內存使用,並在onDraw()執行時間... ... –

相關問題