Kundenspezifische Zeichnung auf Mapbox Karte Leinwand

Ich möchte in der Lage sein, manuell komplexe Formen auf einer Mapbox-Karte mit dem Android-Sdk zu zeichnen. Ich habe die Kartenansicht-Klasse geerbt und das ondraw-Ereignis überschrieben, aber leider, was auch immer ich zeichne, wird von der Karte selbst gezeichnet.

Als Beispiel muss ich in der Lage sein, Polygone mit diamantförmigen Rändern unter anderen komplexen Formen zu zeichnen. Dies kann ich in GoogleMaps kein Problem mit einem benutzerdefinierten Kachel-Provider und Overriding-Ondraw.

Hier ist der einzige Code, den ich bisher für mapbox habe:

@Override public void onDraw(Canvas canvas) { super.onDraw(canvas); Paint stroke = new Paint(); stroke.setColor(Color.BLACK); stroke.setStyle(Paint.Style.STROKE); stroke.setStrokeWidth(5); stroke.setAntiAlias(true); canvas.drawLine(0f,0f,1440f,2464f,stroke); } 

Bildbeschreibung hier eingeben

  • Mapbox Inflate View auf Fragment
  • Mapbox startet nicht in einem Fragment
  • Mapbox Android SDK - Ziehbare Markierung
  • Mapbox GL mit externen Karten
  • Wie bekomme ich ein Klick von Marker mit MapBox SDK?
  • Zeichne einen geographisch genauen Bogen auf einer Karte für Android
  • Java.lang.IllegalArgumentException: bereits hinzugefügt Lokio / AsyncTimeout
  • Auswertung von MapboxGLManager.mapStyles
  • 2 Solutions collect form web for “Kundenspezifische Zeichnung auf Mapbox Karte Leinwand”

    Sie können tun, was Sie wollen auf zwei Arten:

    1) wie Sie vorschlagen: "die MapView Klasse erben und das onDraw() MapView überschreiben". Aber MapView erweitert FrameLayout das ViewGroup , also sollten Sie dispatchDraw() anstelle von onDraw() .

    Dieser Ansatz erfordert eine benutzerdefinierte Ansicht, die MapView und implementiert:

    • Zeichnung über die MapView ;

    • Anpassen von Linienstilen ("Diamanten statt einer einfachen Linie");

    • verbindlicher Pfad zu Lat/Lon Koordinaten von MapView .

    Zum Zeichnen über das MapView sollten Sie dispatchDraw() überschreiben, zB wie MapView :

     @Override public void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); canvas.save(); drawDiamondsPath(canvas); canvas.restore(); } 

    Zum Anpassen von Linienstilen können Sie die setPathEffect () – Methode der Paint Klasse verwenden. Hierfür solltest du einen Pfad für "Diamantstempel" (in Pixeln) erstellen, der jeden "Fortschritt" (auch in Pixeln) wiederholt:

      mPathDiamondStamp = new Path(); mPathDiamondStamp.moveTo(-DIAMOND_WIDTH / 2, 0); mPathDiamondStamp.lineTo(0, DIAMOND_HEIGHT / 2); mPathDiamondStamp.lineTo(DIAMOND_WIDTH / 2, 0); mPathDiamondStamp.lineTo(0, -DIAMOND_HEIGHT / 2); mPathDiamondStamp.close(); mPathDiamondStamp.moveTo(-DIAMOND_WIDTH / 2 + DIAMOND_BORDER_WIDTH, 0); mPathDiamondStamp.lineTo(0, -DIAMOND_HEIGHT / 2 + DIAMOND_BORDER_WIDTH / 2); mPathDiamondStamp.lineTo(DIAMOND_WIDTH / 2 - DIAMOND_BORDER_WIDTH, 0); mPathDiamondStamp.lineTo(0, DIAMOND_HEIGHT / 2 - DIAMOND_BORDER_WIDTH / 2); mPathDiamondStamp.close(); mPathDiamondStamp.setFillType(Path.FillType.EVEN_ODD); mDiamondPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mDiamondPaint.setColor(Color.BLUE); mDiamondPaint.setStrokeWidth(2); mDiamondPaint.setStyle(Paint.Style.FILL_AND_STROKE); mDiamondPaint.setStyle(Paint.Style.STROKE); mDiamondPaint.setPathEffect(new PathDashPathEffect(mPathDiamondStamp, DIAMOND_ADVANCE, DIAMOND_PHASE, PathDashPathEffect.Style.ROTATE)); 

    (in diesem Fall gibt es 2 Path – erste (im Uhrzeigersinn) für den äußeren Rand und den zweiten (gegen den Uhrzeigersinn) für den inneren Rand für "diamond" transparentes "Loch").

    Zum Binden von Pfad auf dem Bildschirm zu Lat/Lon Koordinaten von MapView Du musst das MapboxMap Objekt von MapView – für das muss getMapAsync() und onMapReady() überschrieben werden:

     @Override public void getMapAsync(OnMapReadyCallback callback) { mMapReadyCallback = callback; super.getMapAsync(this); } @Override public void onMapReady(MapboxMap mapboxMap) { mMapboxMap = mapboxMap; if (mMapReadyCallback != null) { mMapReadyCallback.onMapReady(mapboxMap); } } 

    Als Sie können es in "lat / lon-to-screen" konvertieren:

      mBorderPath = new Path(); LatLng firstBorderPoint = mBorderPoints.get(0); PointF firstScreenPoint = mMapboxMap.getProjection().toScreenLocation(firstBorderPoint); mBorderPath.moveTo(firstScreenPoint.x, firstScreenPoint.y); for (int ixPoint = 1; ixPoint < mBorderPoints.size(); ixPoint++) { PointF currentScreenPoint = mMapboxMap.getProjection().toScreenLocation(mBorderPoints.get(ixPoint)); mBorderPath.lineTo(currentScreenPoint.x, currentScreenPoint.y); } 

    Voller Quellcode:

    Benutzerdefinierte DrawMapView.java

     public class DrawMapView extends MapView implements OnMapReadyCallback{ private float DIAMOND_WIDTH = 42; private float DIAMOND_HEIGHT = 18; private float DIAMOND_ADVANCE = 1.5f * DIAMOND_WIDTH; // spacing between each stamp of shape private float DIAMOND_PHASE = DIAMOND_WIDTH / 2; // amount to offset before the first shape is stamped private float DIAMOND_BORDER_WIDTH = 6; // width of diamond border private Path mBorderPath; private Path mPathDiamondStamp; private Paint mDiamondPaint; private OnMapReadyCallback mMapReadyCallback; private MapboxMap mMapboxMap = null; private List<LatLng> mBorderPoints; public DrawMapView(@NonNull Context context) { super(context); init(); } public DrawMapView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } public DrawMapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } public DrawMapView(@NonNull Context context, @Nullable MapboxMapOptions options) { super(context, options); init(); } public void setBorderPoints(List<LatLng> borderPoints) { mBorderPoints = borderPoints; } @Override public void getMapAsync(OnMapReadyCallback callback) { mMapReadyCallback = callback; super.getMapAsync(this); } @Override public void onMapReady(MapboxMap mapboxMap) { mMapboxMap = mapboxMap; if (mMapReadyCallback != null) { mMapReadyCallback.onMapReady(mapboxMap); } } @Override public void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); canvas.save(); drawDiamondsPath(canvas); canvas.restore(); } private void drawDiamondsPath(Canvas canvas) { if (mBorderPoints == null || mBorderPoints.size() == 0) { return; } mBorderPath = new Path(); LatLng firstBorderPoint = mBorderPoints.get(0); PointF firstScreenPoint = mMapboxMap.getProjection().toScreenLocation(firstBorderPoint); mBorderPath.moveTo(firstScreenPoint.x, firstScreenPoint.y); for (int ixPoint = 1; ixPoint < mBorderPoints.size(); ixPoint++) { PointF currentScreenPoint = mMapboxMap.getProjection().toScreenLocation(mBorderPoints.get(ixPoint)); mBorderPath.lineTo(currentScreenPoint.x, currentScreenPoint.y); } mPathDiamondStamp = new Path(); mPathDiamondStamp.moveTo(-DIAMOND_WIDTH / 2, 0); mPathDiamondStamp.lineTo(0, DIAMOND_HEIGHT / 2); mPathDiamondStamp.lineTo(DIAMOND_WIDTH / 2, 0); mPathDiamondStamp.lineTo(0, -DIAMOND_HEIGHT / 2); mPathDiamondStamp.close(); mPathDiamondStamp.moveTo(-DIAMOND_WIDTH / 2 + DIAMOND_BORDER_WIDTH, 0); mPathDiamondStamp.lineTo(0, -DIAMOND_HEIGHT / 2 + DIAMOND_BORDER_WIDTH / 2); mPathDiamondStamp.lineTo(DIAMOND_WIDTH / 2 - DIAMOND_BORDER_WIDTH, 0); mPathDiamondStamp.lineTo(0, DIAMOND_HEIGHT / 2 - DIAMOND_BORDER_WIDTH / 2); mPathDiamondStamp.close(); mPathDiamondStamp.setFillType(Path.FillType.EVEN_ODD); mDiamondPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mDiamondPaint.setColor(Color.BLUE); mDiamondPaint.setStrokeWidth(2); mDiamondPaint.setStyle(Paint.Style.FILL_AND_STROKE); mDiamondPaint.setStyle(Paint.Style.STROKE); mDiamondPaint.setPathEffect(new PathDashPathEffect(mPathDiamondStamp, DIAMOND_ADVANCE, DIAMOND_PHASE, PathDashPathEffect.Style.ROTATE)); canvas.drawPath(mBorderPath, mDiamondPaint); } private void init() { mBorderPath = new Path(); mPathDiamondStamp = new Path(); } } 

    ActivityMain.java

     public class MainActivity extends AppCompatActivity { private DrawMapView mapView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MapboxAccountManager.start(this, getString(R.string.access_token)); setContentView(R.layout.activity_main); mapView = (DrawMapView) findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); mapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(MapboxMap mapboxMap) { mapView.setBorderPoints(Arrays.asList(new LatLng(-36.930129, 174.958843), new LatLng(-36.877860, 174.978108), new LatLng(-36.846373, 174.901841), new LatLng(-36.829215, 174.814659), new LatLng(-36.791326, 174.779337), new LatLng(-36.767680, 174.823242))); } }); } @Override public void onResume() { super.onResume(); mapView.onResume(); } @Override public void onPause() { super.onPause(); mapView.onPause(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); mapView.onSaveInstanceState(outState); } @Override public void onLowMemory() { super.onLowMemory(); mapView.onLowMemory(); } @Override protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); } } 

    activity_main.xml

     <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:mapbox="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="ua.com.omelchenko.mapboxlines.MainActivity"> <ua.com.omelchenko.mapboxlines.DrawMapView android:id="@+id/mapView" android:layout_width="match_parent" android:layout_height="match_parent" mapbox:center_latitude="-36.841362" mapbox:center_longitude="174.851110" mapbox:style_url="@string/style_mapbox_streets" mapbox:zoom="10"/> </RelativeLayout> 

    Schließlich solltest du so etwas bekommen:

    Bildbeschreibung hier eingeben

    Und man sollte einige "Sonderfälle" berücksichtigen, zum Beispiel wenn alle Punkte des Weges außerhalb der aktuellen Ansicht der Karte sind, gibt es keine Zeilen auf ihm, auch Linie sollte Queransicht der Karte und sollte sichtbar sein.

    2) (besserer Weg) erstellen und veröffentlichen Karte mit Ihren zusätzlichen Linien und benutzerdefinierten Stil für sie (vor allem einen Blick auf "Linienmuster mit Bildern" Abschnitte). Sie können dazu Mapbox Studio verwenden . Und bei diesem Ansatz werden alle "Sonderfälle" und Leistungsprobleme auf der Mabpox-Seite gelöst.

    Wenn ich es richtig verstehe, versuchst du, der Karte eine Diamantform hinzuzufügen (der Benutzer zeichnet nicht die Form)? Wenn dies der Fall ist, haben Sie ein paar Optionen:

    1. Verwenden Sie Polygon, fügen Sie einfach die Liste der Punkte und es wird die Form (in diesem Fall ein Diamant) zu zeichnen. Das wäre am einfachsten, aber ich nehme an, du hast es schon ausprobiert und es funktioniert nicht für dich.

       List<LatLng> polygon = new ArrayList<>(); polygon.add(<LatLng Point 1>); polygon.add(<LatLng Point 2>); ... mapboxMap.addPolygon(new PolygonOptions() .addAll(polygon) .fillColor(Color.parseColor("#3bb2d0"))); 
    2. Füge eine Fill-Ebene hinzu, indem du die neue Style-API in 4.2.0 (noch in Beta) eingeführt hast. Andernfalls müssen Sie zunächst ein GeoJSON-Objekt mit Punkten erstellen und dann zur Karte hinzufügen. Das nächste Beispiel, das ich tun muss, wäre dieses Beispiel , das in der Demo-App gefunden wurde.

    3. Verwenden Sie onDraw, die nur die Leinwand in ein GeoJSON-Objekt übersetzen und als eine Ebene hinzufügen möchten, wie in Schritt 2 erklärt. Ich würde es nur empfehlen, wenn Sie den Benutzer während der Laufzeit Formen zeichnen, in diesem Fall sind die Koordinaten unsicher.

    Ich werde diese Antwort bearbeiten, wenn du etwas anderes suchst.

    Das Android ist ein Google Android Fan-Website, Alles ├╝ber Android Phones, Android Wear, Android Dev und Android Spiele Apps und so weiter.