Flutter로 Mapbox 지도를 조작해보세요.

50477 단어 FlutterMapboxtech
Qita에 기고Flutter를 사용하여 Mapbox의 지도를 현재 위치를 중심으로 표시합니다한 후속 내용이다.
젠의 계정을 취득한 뒤 기사를 한 편도 쓰지 않았기 때문에 여기에 써보려고 했습니다.
또 소스 코드GitHub에도 있다(기능 추가 등을 수시로 진행한다).
2021/10/02 보충:
속편을 쓰다.
  • Flutter+Mapbox로 Symbol을 클릭하여 id 가져오기 및 표시
  • Fluter + Mapbox를 사용하여pin (Symbol) 의 정보를 DB (SQLite) 에 저장
  • 2021/10/29 보충:
    mapbox_gl0.1.3 발매에 맞춰 일부 변경이 늘었다.

    마지막으로 설치한 기능

  • Flutter SDK 2.5.3
  • mapbox_gl 0.13.0
  • location 4.3.0
  • 그리고 나서
  • 지도의 표시
  • GPS 추적 ON/OFF
  • ※ 자세한 내용은 저번 보도 참조.

    이번에 추가된 지도 조작 기능

  • 초점(지도의 축척)을 초기 표시
  • 로 회복
  • 화면상=북(초시)귀환
  • 지점별 세로핀
  • 0. 필요한 라이브러리 추가

    pubspec.yamldependencies:에 추가됩니다.
      gap: ^2.0.0
    

    1. 줌(맵 축척)을 초기 디스플레이로 복원


    원래 표시된 배율을 복원하려면 부동 아이콘 버튼(±)을 누릅니다.
      // 地図のズームを初期状態に
      void _resetZoom() {
        _controller.future.then((mapboxMap) {
          mapboxMap.moveCamera(CameraUpdate.zoomTo(_initialZoom));
        });
      }
    
    MapboxMapControllermoveCamera에서만CameraUpdate.zoomTo합니다.

    2. 화면 위 = 북쪽(초기 표시)


    마찬가지로 부동 아이콘 단추 (N) 를 누르면 처음 보이는 방향 (화면 위의 북쪽) 이 회복됩니다.
    2021/10/29 보충(10/30 부분 정정):MapboxMap()를 지정compassEnabled: true으로 표시할 때 화면의 방향(방향)을 변경하면 iOS가 오른쪽 위에 나침반을 표시합니다.이걸 클릭하면 화면 위에 북쪽으로 돌아갑니다.
    그러나 표준 위치라면 오른쪽 상단에 너무 가까워 헤딩이 거의 불가능하기 때문에 아래 지정을 더해 조금만 왼쪽으로 내려가면 2.버튼은 필요 없어요.compassViewMargins: const Point(20.0, 100.0)
      // 地図の上を北に
      void _resetBearing() {
        _controller.future.then((mapboxMap) {
          mapboxMap.animateCamera(CameraUpdate.bearingTo(_initialBearing));
        });
      }
    
    차이가 많지 않다.동시에 CameraUpdate.bearingTo에서 지정0.0하고 화면의 위 = 북쪽으로 향합니다.
    그리고・2.다른 화면으로 이동 중입니다.
  • iOS는 animateCamera
  • 안드로이드는 moveCamera
  • 의 차별화 사용.
    ※ 내가 있는 유기농 재료(Android 10) 중 animateCamera가 제대로 작동하지 않기 때문이다(지도의 회전은 맞지만, 이동은 중도에 멈춘다).

    3. 길게 누르는 곳에 핀을 세운다


    지도의 임의의 지점을 길게 누르면 핀 라벨로 시간을 표시합니다.
    MapBoxMaponMapLongClick에서 다음 코드를 호출합니다.
      // マーク(ピン)を立てて時刻(hh:mm)のラベルを付ける
      void _addMark(LatLng tapPoint) {
        // 時刻を取得
        DateTime _now = DateTime.now();
        String _hhmm = _fillZero(_now.hour) + ':' + _fillZero(_now.minute);
        // マーク(ピン)を立てる
        _controller.future.then((mapboxMap) {
          mapboxMap.addSymbol(SymbolOptions(
            geometry: tapPoint,
            textField: _hhmm,
            textAnchor: "top",
            textColor: "#000",
            textHaloColor: "#FFF",
            textHaloWidth: 3,
            iconImage: "mapbox-marker-icon-blue",
            iconSize: 1,
          ));
        });
      }
    
    MapboxMapControlleraddSymbol에 핀 이미지와 라벨을 추가했습니다.
    ※ 또 날짜 포맷기intl으로 사용하고 싶었는데 dart:html 주변에 고장이 나서 잠시 포기했습니다.
    또 지도(Style)를 미리 준비해야 한다.
  • Add markers : Generic marker images
  • ↓ Download ZIP에서 태그(pin)를 다운로드한 이미지 파일.zip이 동결해제되면 맵박스 스튜디오로 표준 대상의 지도를 편집하고 화면 정보의 이미지 메뉴.svg에 파일을 올린다.

    ※ 이전부터 앱을 사용해 동일한 지도(Style)를 표시했을 때, 캐시에 지도(Style)라는 오래된 정보가 남아있기 때문에 업로드된 이미지는 당분간 표시되지 않을 수 있습니다.

    기타


    나는 지도를 북쪽뿐만 아니라 행진방향도 설치하고 싶었지만 LocationData.heading 나에게만 돌려주고 -1.0해서 포기했다.

    화면 예



    소스 코드


    import 'dart:async';
    import 'dart:io';
    import 'dart:math';
    
    import 'package:flutter/material.dart';
    import 'package:gap/gap.dart';
    import 'package:location/location.dart';
    import 'package:mapbox_gl/mapbox_gl.dart';
    
    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      
      Widget build(BuildContext context) {
        return const MaterialApp(
          title: 'Flutter Mapbox',
          home: MapPage(),
        );
      }
    }
    
    class MapPage extends StatefulWidget {
      const MapPage({Key? key}) : super(key: key);
    
      
      _MapPageState createState() => _MapPageState();
    }
    
    class _MapPageState extends State<MapPage> {
      final Completer<MapboxMapController> _controller = Completer();
      final Location _locationService = Location();
      // 地図スタイル用 Mapbox URL
      final String _style = '【地図スタイルのURL】';
      // Location で緯度経度が取れなかったときのデフォルト値
      final double _initialLat = 35.6895014;
      final double _initialLong = 139.6917337;
      // ズームのデフォルト値
      final double _initialZoom = 13.5;
      // 方位のデフォルト値(北)
      final double _initialBearing = 0.0;
      // 現在位置
      LocationData? _yourLocation;
      // GPS 追従?
      bool _gpsTracking = false;
    
      // 現在位置の監視状況
      StreamSubscription? _locationChangedListen;
    
      
      void initState() {
        super.initState();
    
        // 現在位置の取得
        _getLocation();
    
        // 現在位置の変化を監視
        _locationChangedListen =
            _locationService.onLocationChanged.listen((LocationData result) async {
          setState(() {
            _yourLocation = result;
          });
        });
        setState(() {
          _gpsTracking = true;
        });
      }
    
      
      void dispose() {
        super.dispose();
    
        // 監視を終了
        _locationChangedListen?.cancel();
      }
    
      
      Widget build(BuildContext context) {
        return Scaffold(
          body: _makeMapboxMap(),
          floatingActionButton: _makeFloatingIcons(),
        );
      }
    
      // 地図ウィジェット
      Widget _makeMapboxMap() {
        if (_yourLocation == null) {
          // 現在位置が取れるまではロード中画面を表示
          return const Center(
            child: CircularProgressIndicator(),
          );
        }
        // GPS 追従が ON かつ地図がロードされている→地図の中心を移動
        _moveCameraToGpsPoint();
        // Mapbox ウィジェットを返す
        return MapboxMap(
          // 地図(スタイル)を指定
          styleString: _style,
          // 初期表示される位置情報を現在位置から設定
          initialCameraPosition: CameraPosition(
            target: LatLng(_yourLocation!.latitude ?? _initialLat,
                _yourLocation!.longitude ?? _initialLong),
            zoom: _initialZoom,
          ),
          onMapCreated: (MapboxMapController controller) {
            _controller.complete(controller);
          },
          compassEnabled: true,
          // 現在位置を表示する
          myLocationEnabled: true,
          // 地図をタップしたとき
          onMapClick: (Point<double> point, LatLng tapPoint) {
            _onTap(point, tapPoint);
          },
          // 地図を長押ししたとき
          onMapLongClick: (Point<double> point, LatLng tapPoint) {
            _addMark(tapPoint);
          },
        );
      }
    
      // フローティングアイコンウィジェット
      Widget _makeFloatingIcons() {
        return Column(mainAxisSize: MainAxisSize.min, children: [
          FloatingActionButton(
            backgroundColor: Colors.blue,
            onPressed: () {
              // ズームを戻す
              _resetZoom();
            },
            child: const Text('±', style: TextStyle(fontSize: 28.0, height: 1.0)),
          ),
          const Gap(16),
          FloatingActionButton(
            backgroundColor: Colors.blue,
            onPressed: () {
              // 北向きに戻す
              _resetBearing();
            },
            child: const Text('N',
                style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
          ),
          const Gap(16),
          FloatingActionButton(
            backgroundColor: Colors.blue,
            onPressed: () {
              _gpsToggle();
            },
            child: Icon(
              // GPS 追従の ON / OFF に合わせてアイコン表示する
              _gpsTracking ? Icons.gps_fixed : Icons.gps_not_fixed,
            ),
          ),
        ]);
      }
    
      // 現在位置を取得
      void _getLocation() async {
        _yourLocation = await _locationService.getLocation();
      }
    
      // GPS 追従を ON / OFF
      void _gpsToggle() {
        setState(() {
          _gpsTracking = !_gpsTracking;
        });
        // ここは本来 iOS では不要
        _moveCameraToGpsPoint();
      }
    
      // GPS 追従が ON なら地図の中心を現在位置へ
      void _moveCameraToGpsPoint() {
        if (_gpsTracking) {
          _controller.future.then((mapboxMap) {
            if (Platform.isAndroid) {
              mapboxMap.moveCamera(CameraUpdate.newLatLng(LatLng(
                  _yourLocation!.latitude ?? _initialLat,
                  _yourLocation!.longitude ?? _initialLong)));
            } else if (Platform.isIOS) {
              mapboxMap.animateCamera(CameraUpdate.newLatLng(LatLng(
                  _yourLocation!.latitude ?? _initialLat,
                  _yourLocation!.longitude ?? _initialLong)));
            }
          });
        }
      }
    
      // 地図をタップしたときの処理
      void _onTap(Point<double> point, LatLng tapPoint) {
        _moveCameraToTapPoint(tapPoint);
        setState(() {
          _gpsTracking = false;
        });
      }
    
      // 地図の中心をタップした場所へ
      void _moveCameraToTapPoint(LatLng tapPoint) {
        _controller.future.then((mapboxMap) {
          if (Platform.isAndroid) {
            mapboxMap.moveCamera(CameraUpdate.newLatLng(tapPoint));
          } else if (Platform.isIOS) {
            mapboxMap.animateCamera(CameraUpdate.newLatLng(tapPoint));
          }
        });
      }
    
      // マーク(ピン)を立てて時刻(hh:mm)のラベルを付ける
      void _addMark(LatLng tapPoint) {
        // 時刻を取得
        DateTime _now = DateTime.now();
        String _hhmm = _fillZero(_now.hour) + ':' + _fillZero(_now.minute);
        // マーク(ピン)を立てる
        _controller.future.then((mapboxMap) {
          mapboxMap.addSymbol(SymbolOptions(
            geometry: tapPoint,
            textField: _hhmm,
            textAnchor: "top",
            textColor: "#000",
            textHaloColor: "#FFF",
            textHaloWidth: 3,
            iconImage: "mapbox-marker-icon-blue",
            iconSize: 1,
          ));
        });
      }
    
      // 2 桁 0 埋め(Intl が正しく動かなかったため仕方なく)
      String _fillZero(int number) {
        String _tmpNumber = ('0' + number.toString());
        return _tmpNumber.substring(_tmpNumber.length - 2);
      }
    
      // 地図の上を北に
      void _resetBearing() {
        _controller.future.then((mapboxMap) {
          mapboxMap.animateCamera(CameraUpdate.bearingTo(_initialBearing));
        });
      }
    
      // 地図のズームを初期状態に
      void _resetZoom() {
        _controller.future.then((mapboxMap) {
          mapboxMap.moveCamera(CameraUpdate.zoomTo(_initialZoom));
        });
      }
    }
    

    좋은 웹페이지 즐겨찾기