Vor ein paar Tagen hatte ich die Idee, eine Flutter-App zu bauen, die die Übersetzung eines eingegebenen Wortes für jedes Land in der jeweiligen Sprache auf einer Karte anzeigt. Ich wollte sehen, wie sich Sprachen geografisch entwickeln und verändern.

Ich hatte noch nie mobile Apps entwickelt oder Karten bearbeitet, aber ich wollte es trotzdem versuchen. Da ich meinen Code für iOS, Android und Web kompilieren konnte, ohne auf mehrere Codebasen angewiesen zu sein, entschied ich mich für Flutter. Flutter verfügt außerdem über eine Reihe von Bibliotheken, so dass ich wusste, dass der Einstieg leicht sein würde.
Flutter Map ist ein Open-Source-Paket für Flutter, das ein hochgradig anpassbares Karten-Widget bietet. Mit Flutter Map können Entwickler interaktive Karten in ihren Flutter-Anwendungen erstellen, einschließlich Funktionen wie Markierungen, Polygone, Polylinien und Kachelebenen.
Wie Sie sehen, habe ich oben ein paar Wörter hervorgehoben. Damit begannen meine Probleme. Ich dachte, dass das Erlernen von Flutter meine größte Herausforderung sein würde. Aber zu lernen, wie Karten tatsächlich funktionieren, war für mich ein bisschen kniffliger. Aber bevor ich Ihnen erkläre, warum, lassen Sie uns eine App erstellen, deren einziger Zweck die Anzeige einer Karte mit Flutter Map ist.
Schritt 1: Anzeigen einer Karte mit Flutter
Dies ist der erste Bildschirm, den ich implementiert habe. Eine einfache Karte, mit der ich herumspielen konnte. Wenn ich ein- und auszoome und mich bewege, passt sich die Karte automatisch an und zeigt mehr oder weniger Informationen an, je nachdem, wie stark ich zoome.
Die Anzeige einer Karte ist so einfach wie die Implementierung des folgenden Widgets:
return Scaffold(
body: Stack(
children: [
FlutterMap(
options: MapOptions(
center: LatLng(51.509364, -0.128928),
zoom: 3.2,
),
children: [
TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'com.example.app',
),
],
),
],
),
);
Daraufhin wird der folgende Bildschirm angezeigt:

Ziemlich cool, nicht wahr? Ich hatte gerade meine erste App erstellt, aber ich hatte keine Ahnung, wie ich das gemacht hatte.
Lassen Sie uns also einen Schritt zurückgehen und den Code analysieren, den ich gerade aus der Dokumentation von Flutter Map kopiert und eingefügt habe.
Verstehen der Grundlagen von Flutter (Überspringen Sie diesen Teil, wenn Sie bereits damit vertraut sind)
Sie sehen, dass das von uns erstellte Widget aus einem Scaffold besteht, dessen Körper ein Stack ist und dessen Kind eine FlutterMap ist.
return Scaffold(
body: Stack(
children: [
FlutterMap(
[...]
),
],
),
);
Alles in Flutter ist ein Widget, und Widgets sind nur winzige Teile der Benutzeroberfläche, die Sie zu einer kompletten App kombinieren können. Der Aufbau einer App in Flutter ist wie der Bau eines Legosets - Stück für Stück.
Hätten wir mehrere Kinder in unserem Stapel, würden sie wie in einem echten Stapel übereinander angezeigt werden. Hätten wir anstelle eines Stack-Widgets eine Row oder Column, würden deren Kinder so angezeigt, wie es ihr Name vermuten lässt. Sie müssen nur mit den Widgets herumspielen, damit sie so angezeigt werden, wie Sie es in Ihrer App erwarten.
Tatsächlich brauchten wir für diese einfache Anwendung nicht einmal das Stack and Scaffold Widget auf der Rückseite des FlutterMap Widgets. Wenn wir nur das FlutterMap-Widget zurückgegeben hätten, wäre das Ergebnis dasselbe gewesen.
return FlutterMap(
[...]
);
Zurück zur Flutter-Karte
Das FlutterMap-Widget wird von der Flutter Map-Bibliothek bereitgestellt. Wie Sie sehen können, besteht es aus Optionen und Unterobjekten.
Über die Optionen teilen wir dem Widget mit, dass die Karte in der Mitte von London (51.509364, -0.128928) mit einem Zoom von 3,2 initialisiert werden soll.
Unsere Kinder sind die Ebenen unserer Karte. Für dieses Beispiel benötigen wir nur eine Ebene, nämlich eine Kachel-Ebene, die für das Abrufen der Kartenbilder von Open Street Maps zuständig ist.
Kachel Server URL
Wenn Sie sich unseren TileLayer ansehen, werden Sie feststellen, dass einer der Parameter das urlTemplate ist.
TileLayer(
urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
userAgentPackageName: 'com.example.app',
),
Diese Art von URL wird als "Kachel-Server-URL" bezeichnet. Es handelt sich um ein Standardformat, das von vielen Anbietern von Kartenkacheln verwendet wird, um Kartenkacheln an Mapping-Software zu liefern. In der URL werden die Platzhalter {z}, {x} und {y} verwendet, um die Zoomstufe, die X-Koordinate bzw. die Y-Koordinate der Kachel anzugeben. Wenn eine Karte angezeigt wird, stellt die Mapping-Software für jede Kachel, die zur Darstellung der aktuellen Ansicht benötigt wird, eine Anfrage an die URL des Kachelservers.
Hier sind zwei Kacheln, die in Kombination ganz Portugal zeigen:


Unsere Karte wird aus mehreren nebeneinander angeordneten statischen Bildern erstellt. Wenn wir uns bewegen und ein- und auszoomen, ruft unsere App neue Bilder von der Kachel-Server-URL ab, um unseren Bildschirm mit der Karte zu füllen.
Verschiedene Tile Server URL-Anbieter
Das Wissen über die Tile Server URL führte mich zu meinem nächsten Problem. Open Street Maps zeigt zu viele Informationen an, wenn Sie hineinzoomen. Politische Grenzen, Ländernamen, Straßen, Flüsse... All diese Informationen würden meine Übersetzungen unübersichtlich machen. Ich musste sie loswerden. Aber da die Bilder statisch sind, konnte ich den von OpenStreetMaps bereitgestellten Kachelserver nicht verwenden. Ich musste einen anderen Server finden.
Mit ein paar Google-Suchen konnte ich mehrere Kartenanbieter finden, einige von ihnen kostenpflichtig, andere kostenlos.
Ich wollte etwas Einfaches finden. Nur die Weltkarte mit dem Rand der Länder. Am nächsten kam ich dem, was ich wollte, mit einem Tile Server von Stamen Design mit dem Namen "Toner". Sie bieten sechs verschiedene Geschmacksrichtungen an, und eine davon besteht nur aus dem Hintergrund. Keine Beschriftung. Nahe an dem, was ich brauchte.

Der "Hintergrund" war perfekt für mich, also habe ich mir die Tile Server URL besorgt:
https://stamen-tiles.a.ssl.fastly.net/toner-background/{z}/{x}/{y}.png
Und indem ich das urlTemplate in meinem Widget ersetzte, konnte ich die Ergebnisse sofort sehen:
FlutterMap(
options: MapOptions(
center: LatLng(51.509364, -0.128928),
zoom: 3.2,
),
children: [
TileLayer(
urlTemplate: 'https://stamen-tiles.a.ssl.fastly.net/toner-background/{z}/{x}/{y}.png',
userAgentPackageName: 'com.example.app',
),
],
);

Schritt 2: Platzieren eines Labels auf der Karte
Meine Idee ist es, eine App zu entwickeln, in der ich ein Wort eingeben und die Übersetzung dieses Wortes für jedes Land in der jeweiligen Sprache sehen kann. Jetzt, wo ich eine Karte habe, musste ich einen Weg finden, um Beschriftungen für bestimmte Koordinaten anzuzeigen.
Kartenebenen
Lassen Sie uns auf einen früheren Absatz zurückblicken:
(In Flutter Map) Unsere Kinder sind die Ebenen unserer Karte. Für dieses Beispiel benötigen wir nur eine Ebene, nämlich eine Kachel-Ebene, die für das Abrufen der Kartenbilder von Open Street Maps zuständig ist.
Unsere Karte besteht aus übereinander angeordneten Ebenen. Für das vorherige Beispiel benötigten wir nur eine Ebene: TileLayer. Die Flutter Map-Bibliothek bietet jedoch noch andere Arten von Ebenen, wie MarkerLayer, PolygonLayer, PolylineLayer, CircleLayer und AttributionLayer.
PolygonLayer
Die Polygonebene wird verwendet, um ein Polygon über unserer Karte anzuzeigen. Schauen wir uns das mal an:
PolygonLayer(
polygonCulling: false,
polygons: [
Polygon(
points: [
LatLng(36.95, -9.5),
LatLng(42.25, -9.5),
LatLng(42.25, -6.2),
LatLng(36.95, -6.2),
],
color: Colors.blue.withOpacity(0.5),
borderStrokeWidth: 2,
borderColor: Colors.blue,
isFilled: true
),
],
)
Im obigen Beispiel wird ein PolygonLayer-Widget erstellt, mit dem Sie ein oder mehrere Polygone auf der Karte anzeigen können.
Das PolygonLayer-Widget nimmt eine Liste von Polygon-Objekten als Parameter polygons. In diesem Fall ist nur ein Polygon in der Liste definiert.
Die Klasse Polygon wird verwendet, um ein Polygon auf der Karte zu definieren. Sie benötigt mehrere Parameter, um die Form, die Position und das Aussehen des Polygons zu definieren.
Der Parameter polygonCulling ist ein boolescher Wert, der angibt, ob Polygone, die vollständig außerhalb des sichtbaren Bereichs der Karte liegen, aussortiert (entfernt) werden sollen. Die Einstellung false bedeutet, dass alle Polygone gerendert werden, unabhängig davon, ob sie sich außerhalb des sichtbaren Bereichs der Karte befinden.
In diesem Beispiel wird das Polygon mit einem points-Parameter definiert, der eine Liste von LatLng-Objekten ist, die die Scheitelpunkte des Polygons definieren. Der Parameter color gibt die Füllfarbe des Polygons an. In diesem Fall platzieren wir ein Quadrat über Portugal. Schauen wir uns an, wie es aussieht:

PolylineLayer
PolylineLayer(
polylines: [
Polyline(
points: [
LatLng(38.73, -9.14), // Lisbon, Portugal
LatLng(51.50, -0.12), // London, United Kingdom
LatLng(52.37, 4.90), // Amsterdam, Netherlands
],
color: Colors.blue,
strokeWidth: 2,
),
],
)
Das obige Beispiel erstellt ein PolylineLayer-Widget, mit dem Sie eine oder mehrere Polylinien auf der Karte anzeigen können.
Das PolylineLayer-Widget akzeptiert eine Liste von Polyline-Objekten als Parameter für Polylinien. In diesem Fall ist nur eine Polylinie in der Liste definiert.
Die Klasse Polyline wird verwendet, um eine Polylinie auf der Karte zu definieren. Sie benötigt mehrere Parameter, um die Form, die Position und das Aussehen der Polylinie zu definieren.
In diesem Beispiel wird die Polyline mit einem points-Parameter definiert, der eine Liste von LatLng-Objekten ist, die die Scheitelpunkte der Polyline definieren. Der Parameter color gibt die Farbe der Polylinie an. Wir zeichnen also eine Linie, die die Hauptstädte von Portugal, England und den Niederlanden verbindet.

CircleLayer
CircleLayer(
circles: [
CircleMarker(
point: LatLng(52.2677, 5.1689), // center of 't Gooi
radius: 5000,
useRadiusInMeter: true,
color: Colors.red.withOpacity(0.3),
borderColor: Colors.red.withOpacity(0.7),
borderStrokeWidth: 2,
)
],
)
Das obige Beispiel erstellt ein CircleLayer-Widget, mit dem Sie einen oder mehrere Kreise auf der Karte anzeigen können.
Das CircleLayer Widget nimmt eine Liste von CircleMarker Objekten als Parameter für Kreise an. In diesem Fall ist nur ein Kreis in der Liste definiert.
Die Klasse CircleMaker wird verwendet, um einen Kreis auf der Karte zu definieren. Sie benötigt mehrere Parameter, um die Form, die Position und das Aussehen des Kreises zu bestimmen.
In diesem Beispiel wird der CircleMarker mit einem Point-Parameter definiert, der die Position der Markierung auf der Karte als LatLng-Objekt angibt. Der Parameter color gibt die Farbe des Kreises an und der Parameter radius die Größe des Kreises.
Wir ziehen einen Kreis über das Gebiet 't Gooi in den Niederlanden mit einem Radius von 5 km.

MarkerLayer
Die Markierungsebene ist die einfachste Ebene. Wir verwenden sie für die Anzeige eines Widgets auf einer bestimmten Koordinate. Schauen wir uns das mal an:
MarkerLayer(
markers: [
Marker(
point: LatLng(51.509364, -0.128928),
width: 80,
height: 80,
builder: (context) => FlutterLogo(),
),
],
)
Im obigen Beispiel erstellen wir ein MarkerLayer-Widget, das dazu dient, eine oder mehrere Markierungen auf der Karte anzuzeigen.
Das MarkerLayer-Widget akzeptiert eine Liste von Marker-Objekten als Marker-Parameter. In diesem Fall ist nur eine Markierung in der Liste definiert.
Die Klasse Marker wird verwendet, um eine Markierung auf der Karte zu definieren. Sie benötigt mehrere Parameter, um die Position, die Größe und das Aussehen der Markierung festzulegen.
In diesem Beispiel wird die Markierung mit einem Punkt-Parameter definiert, der die Position der Markierung auf der Karte als LatLng-Objekt angibt. Die Parameter width und height geben die Größe der Markierung in Pixeln an und der Parameter builder nimmt eine Funktion auf, die ein Widget zurückgibt, um das Aussehen der Markierung zu definieren.
In diesem Beispiel verwendet die Builder-Funktion das FlutterLogo-Widget, um ein Flutter-Logo an der Stelle anzuzeigen, die durch den Parameter point angegeben wurde, nämlich London.

Wörter auf der Karte platzieren
Wie ich bereits sagte, ist es mein Ziel, Wörter auf der Karte zu platzieren, und der MarkerLayer ist die perfekte Lösung dafür.
Bevor wir unsere Markierungen erstellen, lassen Sie uns unsere Text-Widgets erstellen. Wir beginnen mit dem Stil:
TextStyle getDefaultTextStyle() {
return const TextStyle(
fontSize: 12,
backgroundColor: Colors.black,
color: Colors.white,
);
}
Diese Methode gibt ein TextStyle-Objekt zurück, das die Schriftgröße, die Hintergrundfarbe und die Farbe der Schrift definiert. Es wird verwendet von:
Container buildTextWidget(String word) {
return Container(
alignment: Alignment.center,
child: Text(
word,
textAlign: TextAlign.center,
style: getDefaultTextStyle()
)
);
}
Unser Text-Widget erhält ein Wort als Text und wird in einem Container-Widget platziert.
Marker buildMarker(LatLng coordinates, String word) {
return Marker(
point: coordinates,
width: 100,
height: 12,
builder: (context) => buildTextWidget(word)
);
}
Die Funktion buildTextWidget wird innerhalb unserer Funktion buildMarker aufgerufen, um die Marker zu erstellen, die die Kinder unseres Widgets MarkerLayer sein werden. Sie werden mit den Koordinaten erstellt, an denen sie platziert werden sollen, und mit dem Wort, das sie anzeigen sollen.
MarkerLayer(
markers: [
buildMarker(LatLng(39.3999, -8.2245), "Amor"), // Portugal
buildMarker(LatLng(55.3781, -3.4360), "Love"), // England
buildMarker(LatLng(46.2276, 2.2137), "Aimer"), // France
buildMarker(LatLng(52.1326, 5.2913), "Liefde"), // Netherlands
buildMarker(LatLng(51.1657, 10.4515), "Liebe"), // Germany
],
)
Und schließlich:

Fazit
In dieser Geschichte haben wir gelernt, wie Karten gerendert werden und welche Möglichkeiten es gibt, wenn es um Tile Server geht.
Außerdem haben wir gelernt, wie unsere Karte in Ebenen unterteilt ist und wie wir diese nutzen können, um Markierungen, Polygone, Polylinien und Kreise auf bestimmten Koordinaten zu platzieren.
Abschließend haben wir anhand eines praktischen Beispiels gelernt, wie man Textbeschriftungen über bestimmten Ländern auf unserer Karte anzeigt.
Was kommt als Nächstes?
Meine Reise mit Flutter hat gerade erst begonnen. Dies ist nur die Oberfläche der ersten App, die ich gebaut habe.
In meinen nächsten Beiträgen werde ich zeigen, wie ich es dem Benutzer ermöglicht habe, ein Wort einzugeben und dieses Wort in mehrere Sprachen zu übersetzen, damit es auf der Karte angezeigt werden kann.
Außerdem zeige ich Ihnen, wie Sie Ihre Karte auf fortgeschrittenere Weise manipulieren können, z. B. durch Vergrößern und Verkleinern der Beschriftungen beim Vergrößern und Verkleinern, und wie Sie einen Karten-Controller implementieren, um Schaltflächen anstelle von Gesten zur Steuerung unserer Karte zu verwenden.
Bleiben Sie dran!
Diese Geschichte ist auch auf YouTube verfügbar!
[embed]https://youtu.be/YuwhlhaM1eM[/embed]
Verfasst von

Raphael De Lio
I talk about technology
Unsere Ideen
Weitere Blogs
Contact




