Openstreetmap in Flutter?

Can we use Openstreetmap in Flutter or can we only use Google Maps? I wanted to get another way to display a Map. Cause when using googlemaps api key they need to know a Credit Card and i dont have one.


Solution 1:

You can use the below plugin. An example is included in the repository.

https://github.com/apptreesoftware/flutter_map

Pub.dev link:

https://pub.dev/packages/flutter_map

Solution 2:

You may check out the below Flutter Maps widget which allows you to render tiles from services like OpenStreetMaps which does not require billing.

https://pub.dev/packages/syncfusion_flutter_maps

OpenStreetMaps may be used free of cost. However, I would recommend you to check the licensing terms on their official website and ensure it.

Solution 3:

Declare these dependencies in your pubspec.yaml

  era_geojson: "^0.1.1+4"
  latlong: "^0.5.3"

Then you can write your custom map like this:

import 'package:flutter/material.dart';

class CustomMap extends CustomPainter {
  Size screenSize;
  List<Offset> pointsRoads;
  List<Offset> pointsBuilding;
  List<Path> pointsBuildings;
  final bgColor = const Color(0xFFF7F7F7);
  final borderColor = const Color(0xFFCBCBCB);
  final buildingColor = const Color(0xFFEFEFEF);
  double scale = 1.0;
  Offset delta = Offset.zero;

  final Paint paintRoads = Paint()
    ..color = Colors.white
    ..strokeCap = StrokeCap.round
    ..strokeWidth = 3.0;
  final Paint paintBorder = Paint()
    ..color = Colors.black12
    ..strokeCap = StrokeCap.round
    ..strokeWidth = 4.0;

  final Paint paintBuilding = Paint()
    ..color = Color(0xFFEFEFEF)
    ..strokeCap = StrokeCap.round
    ..strokeWidth = 1.0;

  final Paint paintBuildingBorder = Paint()
    ..color = Color(0xFFEFEFEF)
    ..strokeCap = StrokeCap.round
    ..strokeWidth = 1.0;

  CustomMap(
      {this.delta,
      this.scale,
      this.pointsRoads,
      this.pointsBuilding,
      this.pointsBuildings,
      this.screenSize});

  @override
  void paint(Canvas canvas, Size size) {
    canvas.translate(delta.dx, delta.dy);
    canvas.scale(scale, scale);
    canvas.drawColor(bgColor, BlendMode.color);
    // Roads Start
    if (pointsRoads != null && pointsRoads.length > 0) {
      var start = DateTime.now().millisecondsSinceEpoch;
      for (int i = 0; i < pointsRoads.length - 1; i++) {
        if (isInScreen(pointsRoads[i], pointsRoads[i + 1])) {
          canvas.drawLine(pointsRoads[i], pointsRoads[i + 1], paintBorder);
        }
      }
      var end = DateTime.now().millisecondsSinceEpoch;
      print("Draw Roads Border: ${end - start}");

      var start2 = DateTime.now().millisecondsSinceEpoch;
      for (int i = 0; i < pointsRoads.length - 1; i++) {
        if (isInScreen(pointsRoads[i], pointsRoads[i + 1])) {
          canvas.drawLine(pointsRoads[i], pointsRoads[i + 1], paintRoads);
        }
      }
      var end2 = DateTime.now().millisecondsSinceEpoch;
      print("Draw Roads: ${end2 - start2}");
    }
    // Roads End

    // Buildings Start
    var start = DateTime.now().millisecondsSinceEpoch;
    for (int i = 0; i < pointsBuildings.length - 1; i++) {
      canvas.drawPath(pointsBuildings[i], paintBuilding);
    }
    var end = DateTime.now().millisecondsSinceEpoch;
    print("Draw Buildings: ${end - start}");

    if (pointsBuilding != null && pointsBuilding.length > 0) {
      var start = DateTime.now().millisecondsSinceEpoch;
      for (int i = 0; i < pointsBuilding.length - 1; i++) {
        if (isInScreen(pointsBuilding[i], pointsBuilding[i + 1])) {
          canvas.drawLine(
              pointsBuilding[i], pointsBuilding[i + 1], paintBuildingBorder);
        }
      }
      var end = DateTime.now().millisecondsSinceEpoch;
      print("Draw Buildings Border: ${end - start}");
    }
    // Buildings End
  }

  bool isInScreen(Offset first, Offset second) {
    if (first != null && second != null) {
      first = first.scale(scale, scale);
      second = second.scale(scale, scale);
      if ((first.dx > -1 &&
              first.dy > -1 &&
              first.dx < this.screenSize.width &&
              first.dy < this.screenSize.height) ||
          (second.dx > -1 &&
              second.dy > -1 &&
              second.dx < this.screenSize.width &&
              second.dy < this.screenSize.height)) {
        return true;
      }
    }
    return false;
  }

  @override
  bool shouldRepaint(CustomMap oldDelegate) => true;
}

and use it in a wrapping GestureDetector like this:

GestureDetector(
          onPanUpdate: (DragUpdateDetails details) {
            setState(() {
              _delta = _delta + details.delta;
            });
          },
          child: CustomPaint(
              painter: CustomMap(
                  scale: _scale,
                  delta: _delta,
                  pointsRoads: _roadsPoints,
                  pointsBuilding: _buildingPoints,
                  pointsBuildings: _pointsBuildings,
                  screenSize: screenSize),
              size: Size.infinite) // CustomPaint
          ) 

See this complete example: https://github.com/aoinakanishi/flutter-openstreetmap-example