Flutter로 Mapbox 지도를 조작해보세요.
젠의 계정을 취득한 뒤 기사를 한 편도 쓰지 않았기 때문에 여기에 써보려고 했습니다.
또 소스 코드GitHub에도 있다(기능 추가 등을 수시로 진행한다).
2021/10/02 보충:
속편을 쓰다.
mapbox_gl0.1.3 발매에 맞춰 일부 변경이 늘었다.
마지막으로 설치한 기능
이번에 추가된 지도 조작 기능
0. 필요한 라이브러리 추가
pubspec.yaml
의 dependencies:
에 추가됩니다. gap: ^2.0.0
1. 줌(맵 축척)을 초기 디스플레이로 복원
원래 표시된 배율을 복원하려면 부동 아이콘 버튼(±)을 누릅니다.
// 地図のズームを初期状態に
void _resetZoom() {
_controller.future.then((mapboxMap) {
mapboxMap.moveCamera(CameraUpdate.zoomTo(_initialZoom));
});
}
MapboxMapController의moveCamera에서만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.다른 화면으로 이동 중입니다.
※ 내가 있는 유기농 재료(Android 10) 중 animateCamera가 제대로 작동하지 않기 때문이다(지도의 회전은 맞지만, 이동은 중도에 멈춘다).
3. 길게 누르는 곳에 핀을 세운다
지도의 임의의 지점을 길게 누르면 핀 라벨로 시간을 표시합니다.
MapBoxMap의 onMapLongClick에서 다음 코드를 호출합니다.
// マーク(ピン)を立てて時刻(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,
));
});
}
MapboxMapController의 addSymbol에 핀 이미지와 라벨을 추가했습니다.※ 또 날짜 포맷기intl으로 사용하고 싶었는데
dart:html
주변에 고장이 나서 잠시 포기했습니다.또 지도(Style)를 미리 준비해야 한다.
.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));
});
}
}
Reference
이 문제에 관하여(Flutter로 Mapbox 지도를 조작해보세요.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/hmatsu47/articles/846c3186f5b4fe텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)