flutter - 让相机移动到 Flutter Map (Mapbox) 中的点击标记
问题描述
我正在使用 Flutter 地图包(https://pub.dev/packages/flutter_map),因为我不想在这个项目中使用 Googlemaps。问题是我从未使用过它并且文档很差,所以我无法将相机移动到点击标记:
mapController.move(LatLng(latitude, longitude), 10.0);
当然还有像上面这样声明地图控制器:
MapController mapController = MapController();
基本上,移动功能应该在Tap上工作,但由于某种原因它不起作用,它给了我一些奇怪的运行时错误,任何想法我做错了什么?
这是代码:
Widget loadMap() {
...Streambuilder...
builder: (context, snapshot) {
if (!snapshot.hasData) return Text('Loading maps... Please wait');
for (int i = 0; i < snapshot.data.docs.length; i++) {
allMarkers.add(Marker(
width: 45.0,
height: 45.0,
point: LatLng(
snapshot.data.docs[i]['location'].latitude,
snapshot.data.docs[i]['location'].longitude,
),
builder: (context) => Column(
children: [
Expanded(
child: Container(
child: IconButton(
icon: Icon(Icons
.location_on),
color: _markerColor,
iconSize: 45.0,
onPressed: () {
//this doesn't work here
mapController.move(LatLng(latitude, longitude), 10.0);
print(snapshot.data.docs[i]['eventName']);
showModalBottomSheet(
isDismissible:
false,
context: context,
builder: (builder) {
if (snapshot.data.docs[i]['description'].length >
0) {
//not the most elegant solution
}
});
//this returns error when marker is clicked, and doesn't move the camera to the marker
mapController.move(
LatLng(
snapshot.data.docs[i]['location'].latitude,
snapshot.data.docs[i]['location'].longitude,
),
10.0);
},
),
),
),
],
),
));
}
return FlutterMap(
//flutter map displayed with Mapbox
);
},
}
在 initState 中添加了地图控制器,但仍然出现错误:
void initState() {
super.initState();
mapController = MapController();
}
-错误:
The following LateError was thrown while handling a gesture:
LateInitializationError: Field '_state@244051772' has not been initialized.
When the exception was thrown, this was the stack
#0 MapControllerImpl._state (package:flutter_map/src/map/map.dart)
package:flutter_map/…/map/map.dart:1
#1 MapControllerImpl.move
package:flutter_map/…/map/map.dart:41
#2 _MapScreenState.loadMap.<anonymous closure>.<anonymous closure>.<anonymous closure>
package:directr/pages/map_screen.dart:67
解决方案
前言:是的,HTML 文档不是很详细,但是在代码示例方面的文档令人惊叹——所有内容都有示例。如果您正在寻找文档,还请检查任何库的“example”文件夹和“test”文件夹——它们大多数时候比 HTML 文档有用得多。
如果您没有自己投入工作,请不要在提及其他人的工作时使用“差”之类的词。
我刚刚检查的库的“示例”文件夹中有一个工作示例,它正在工作,如果您希望我们解决您的特定问题,请提供一个可以执行的完整示例。
下面的代码已更改为能够在没有示例文件夹中的其他文件的情况下“独立”运行它,但我没有功劳。
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:location/location.dart';
class MapControllerPage extends StatefulWidget {
static const String route = 'map_controller';
@override
MapControllerPageState createState() {
return MapControllerPageState();
}
}
class MapControllerPageState extends State<MapControllerPage> {
static LatLng london = LatLng(51.5, -0.09);
static LatLng paris = LatLng(48.8566, 2.3522);
static LatLng dublin = LatLng(53.3498, -6.2603);
late final MapController mapController;
double rotation = 0.0;
@override
void initState() {
super.initState();
mapController = MapController();
}
@override
Widget build(BuildContext context) {
var markers = <Marker>[
Marker(
width: 80.0,
height: 80.0,
point: london,
builder: (ctx) => Container(
key: Key('blue'),
child: FlutterLogo(),
),
),
Marker(
width: 80.0,
height: 80.0,
point: dublin,
builder: (ctx) => Container(
child: FlutterLogo(
key: Key('green'),
textColor: Colors.green,
),
),
),
Marker(
width: 80.0,
height: 80.0,
point: paris,
builder: (ctx) => Container(
key: Key('purple'),
child: FlutterLogo(textColor: Colors.purple),
),
),
];
return Scaffold(
appBar: AppBar(title: Text('MapController')),
body: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Row(
children: <Widget>[
MaterialButton(
onPressed: () {
mapController.move(london, 18.0);
},
child: Text('London'),
),
MaterialButton(
onPressed: () {
mapController.move(paris, 5.0);
},
child: Text('Paris'),
),
MaterialButton(
onPressed: () {
mapController.move(dublin, 5.0);
},
child: Text('Dublin'),
),
CurrentLocation(mapController: mapController),
],
),
),
Padding(
padding: EdgeInsets.only(top: 8.0, bottom: 8.0),
child: Row(
children: <Widget>[
MaterialButton(
onPressed: () {
var bounds = LatLngBounds();
bounds.extend(dublin);
bounds.extend(paris);
bounds.extend(london);
mapController.fitBounds(
bounds,
options: FitBoundsOptions(
padding: EdgeInsets.only(left: 15.0, right: 15.0),
),
);
},
child: Text('Fit Bounds'),
),
Builder(builder: (BuildContext context) {
return MaterialButton(
onPressed: () {
final bounds = mapController.bounds!;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'Map bounds: \n'
'E: ${bounds.east} \n'
'N: ${bounds.north} \n'
'W: ${bounds.west} \n'
'S: ${bounds.south}',
),
));
},
child: Text('Get Bounds'),
);
}),
Text('Rotation:'),
Expanded(
child: Slider(
value: rotation,
min: 0.0,
max: 360,
onChanged: (degree) {
setState(() {
rotation = degree;
});
mapController.rotate(degree);
},
),
)
],
),
),
Flexible(
child: FlutterMap(
mapController: mapController,
options: MapOptions(
center: LatLng(51.5, -0.09),
zoom: 5.0,
maxZoom: 5.0,
minZoom: 3.0,
),
layers: [
TileLayerOptions(
urlTemplate:
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c']),
MarkerLayerOptions(markers: markers)
],
),
),
],
),
),
);
}
}
class CurrentLocation extends StatefulWidget {
const CurrentLocation({
Key? key,
required this.mapController,
}) : super(key: key);
final MapController mapController;
@override
_CurrentLocationState createState() => _CurrentLocationState();
}
class _CurrentLocationState extends State<CurrentLocation> {
int _eventKey = 0;
var icon = Icons.gps_not_fixed;
late final StreamSubscription<MapEvent> mapEventSubscription;
@override
void initState() {
super.initState();
mapEventSubscription =
widget.mapController.mapEventStream.listen(onMapEvent);
}
@override
void dispose() {
mapEventSubscription.cancel();
super.dispose();
}
void setIcon(IconData newIcon) {
if (newIcon != icon && mounted) {
setState(() {
icon = newIcon;
});
}
}
void onMapEvent(MapEvent mapEvent) {
if (mapEvent is MapEventMove && mapEvent.id == _eventKey.toString()) {
setIcon(Icons.gps_not_fixed);
}
}
void _moveToCurrent() async {
_eventKey++;
var location = Location();
try {
var currentLocation = await location.getLocation();
var moved = widget.mapController.move(
LatLng(currentLocation.latitude!, currentLocation.longitude!),
18,
id: _eventKey.toString(),
);
if (moved) {
setIcon(Icons.gps_fixed);
} else {
setIcon(Icons.gps_not_fixed);
}
} catch (e) {
setIcon(Icons.gps_off);
}
}
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(icon),
onPressed: _moveToCurrent,
);
}
}
推荐阅读
- sql - 从表中选择不同的 ID
- mysql - MySQLSyntaxErrorException 'OPTION SQL_SELECT_LIMIT=DEFAULT'
- python - 在 -if- 语句中询问两个对象而不在第二个对象中指定问题
- haskell - Haskell 的论据太少?
- r - R基本图形在Mac上将字体更改为Times new roman regular
- python - 如何从 azure blob 存储中读取 parquet 文件(大尺寸 1 GB)而不在本地机器上下载
- database - 2PC(2阶段提交)和2 PL(2阶段锁定)之间的区别
- android - 模拟器总是崩溃并出现错误“等待设备时出错:AVD 的模拟器进程已终止”
- angular - 角度问题(无法读取未定义的属性“流派”)
- python - 如何从pyhton中的ndarray(预测值)一张一张地显示/显示图像?