flutter_map 通过 BLoC 使用地图控制器移动相机
flutter_map move camera with map controller through BLoC
我正在使用 BLoC 模式和 flutter_map 包构建一个 flutter 应用程序。我想将相机移动到特定位置。我正在尝试将地图控制器传递到我的 bloc 结构并从那里移动相机,但我收到错误消息:
NoSuchMethodError: The getter 'onReady' was called on null.
我不确定这是否是正确的方法。
class HomePage extends StatelessWidget {
const HomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
...,
BlocProvider<MapBloc>(
create: (BuildContext context) => MapBloc(mapController: MapController()) // passing map controller
..add(MapDataInit()),
)
],
...
);
}
}
map_bloc.dart
class MapBloc extends Bloc<MapEvent, MapState> {
final MapController mapController;
LocationRepository _locationRepository = LocationRepository();
MapBloc({@required this.mapController});
@override
get initialState => MapDataUninitialized();
@override
Stream<MapState> mapEventToState(MapEvent event) async* {
final currentState = state;
if (event is AddMarker) {
yield MapDataLoaded(
mapController: this.mapController,
markers: [...]);
this.add(MoveCamera(event.latLan)); // not sure about this
}
if (event is MoveCamera) {
mapController.onReady.then((result) { // i'm getting an error here
mapController.move(event.latLan, 15.0);
});
}
}
}
带地图的小部件
class SelectLocationView extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder<MapBloc, MapState>(
builder: (context, state) {
...
if (state is MapDataLoaded) {
return Container(
child: Center(
child: Container(
child: FlutterMap(
mapController: state.mapController, // I'm trying to get previously defined controller
options: MapOptions(...),
layers: [
TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']),
MarkerLayerOptions(...),
],
))),
);
}
},
);
}
}
我不知道为什么地图控制器的 onReady 方法有问题。
我在使用 GetX 时遇到了类似的问题。
我决定应用一些前提:首先,我在 Widget(无状态)中保留了对地图的所有操作 ,因为我需要在 google 插件和 flutter_map.
然后,在控制器中(在你的 BloC 中),它只是触发必要的信息,以便视图从它接收必须居中的新位置,但是视图是知道和集中地图而不是 BloC.
的人
简而言之,我不得不使用静态变量来保持应用程序中 mapController 的单例引用,因为“onReady ()”方法只被调用一次,所以我保留了 bool 来控制地图,而当“onReady”未执行时,我们无权访问地图对象,例如“缩放”和“移动”。
我的示例代码:
class FlutterMapWidget extends StatelessWidget {
static MapController _mapController;
bool isMapRead = false;
FlutterMapWidget() {
// create instance only not exists another reference
if(_mapController == null) {
_mapController = MapController();
}
// after onReady, flag local control variable
_mapController.onReady.then((v) {
isMapRead = _mapController.ready;
});
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
_buildMap(),
// add another map components ...
],
);
}
void _gotoLocation(double lat,double long) {
//check if map is ready to move camera...
if(this.isMapRead) {
_mapController.move(LatLng(lat, long), _mapController?.zoom);
}
}
Widget _buildMap(){
return GetBuilder<MapEventsController>( // GetX state control
init: _mapEventsController, // GetX events controller
builder: (value) { // GetX event fire when update state in controller
updatePinOnMap(value.liveUpdate, value.location);
if(value.liveUpdate){
_gotoLocation(value.location.lat, value.location.lng);
}
return FlutterMap(
mapController: _mapController,
options: MapOptions(
center: LatLng(value?.location?.lat, value?.location?.lng),
zoom: 13.0,
plugins: [
],
onTap: _handleTap,
),
layers: [
TileLayerOptions(
urlTemplate:
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c']
),
MarkerLayerOptions(markers: markers), //markers
],
);
},
);
}
void updatePinOnMap(bool liveUpdate, Location location) async {
if(location == null) {
return;
}
this.markers.clear();
Marker mark = Marker(
point: LatLng(location.lat, location.lng),
anchorPos: anchorPos,
builder: (ctx) =>
GestureDetector(
onTap: () => _configureModalBottomSheet(ctx),
child: Container(
child: Icon(Icons.my_location, size: 28, color: Colors.red,), // FlutterLogo(),
),
),
);
markers.add(mark);
}
void _handleTap(LatLng latlng) {
}
void _configureModalBottomSheet(context) {
}
}
听起来很蠢,但是你在初始化地图控制器吗?
像
MapController mapController = MapController();
我正在使用 BLoC 模式和 flutter_map 包构建一个 flutter 应用程序。我想将相机移动到特定位置。我正在尝试将地图控制器传递到我的 bloc 结构并从那里移动相机,但我收到错误消息:
NoSuchMethodError: The getter 'onReady' was called on null.
我不确定这是否是正确的方法。
class HomePage extends StatelessWidget {
const HomePage({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
...,
BlocProvider<MapBloc>(
create: (BuildContext context) => MapBloc(mapController: MapController()) // passing map controller
..add(MapDataInit()),
)
],
...
);
}
}
map_bloc.dart
class MapBloc extends Bloc<MapEvent, MapState> {
final MapController mapController;
LocationRepository _locationRepository = LocationRepository();
MapBloc({@required this.mapController});
@override
get initialState => MapDataUninitialized();
@override
Stream<MapState> mapEventToState(MapEvent event) async* {
final currentState = state;
if (event is AddMarker) {
yield MapDataLoaded(
mapController: this.mapController,
markers: [...]);
this.add(MoveCamera(event.latLan)); // not sure about this
}
if (event is MoveCamera) {
mapController.onReady.then((result) { // i'm getting an error here
mapController.move(event.latLan, 15.0);
});
}
}
}
带地图的小部件
class SelectLocationView extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder<MapBloc, MapState>(
builder: (context, state) {
...
if (state is MapDataLoaded) {
return Container(
child: Center(
child: Container(
child: FlutterMap(
mapController: state.mapController, // I'm trying to get previously defined controller
options: MapOptions(...),
layers: [
TileLayerOptions(
urlTemplate:
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
subdomains: ['a', 'b', 'c']),
MarkerLayerOptions(...),
],
))),
);
}
},
);
}
}
我不知道为什么地图控制器的 onReady 方法有问题。
我在使用 GetX 时遇到了类似的问题。
我决定应用一些前提:首先,我在 Widget(无状态)中保留了对地图的所有操作 ,因为我需要在 google 插件和 flutter_map.
然后,在控制器中(在你的 BloC 中),它只是触发必要的信息,以便视图从它接收必须居中的新位置,但是视图是知道和集中地图而不是 BloC.
的人简而言之,我不得不使用静态变量来保持应用程序中 mapController 的单例引用,因为“onReady ()”方法只被调用一次,所以我保留了 bool 来控制地图,而当“onReady”未执行时,我们无权访问地图对象,例如“缩放”和“移动”。
我的示例代码:
class FlutterMapWidget extends StatelessWidget {
static MapController _mapController;
bool isMapRead = false;
FlutterMapWidget() {
// create instance only not exists another reference
if(_mapController == null) {
_mapController = MapController();
}
// after onReady, flag local control variable
_mapController.onReady.then((v) {
isMapRead = _mapController.ready;
});
}
@override
Widget build(BuildContext context) {
return Stack(
children: [
_buildMap(),
// add another map components ...
],
);
}
void _gotoLocation(double lat,double long) {
//check if map is ready to move camera...
if(this.isMapRead) {
_mapController.move(LatLng(lat, long), _mapController?.zoom);
}
}
Widget _buildMap(){
return GetBuilder<MapEventsController>( // GetX state control
init: _mapEventsController, // GetX events controller
builder: (value) { // GetX event fire when update state in controller
updatePinOnMap(value.liveUpdate, value.location);
if(value.liveUpdate){
_gotoLocation(value.location.lat, value.location.lng);
}
return FlutterMap(
mapController: _mapController,
options: MapOptions(
center: LatLng(value?.location?.lat, value?.location?.lng),
zoom: 13.0,
plugins: [
],
onTap: _handleTap,
),
layers: [
TileLayerOptions(
urlTemplate:
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c']
),
MarkerLayerOptions(markers: markers), //markers
],
);
},
);
}
void updatePinOnMap(bool liveUpdate, Location location) async {
if(location == null) {
return;
}
this.markers.clear();
Marker mark = Marker(
point: LatLng(location.lat, location.lng),
anchorPos: anchorPos,
builder: (ctx) =>
GestureDetector(
onTap: () => _configureModalBottomSheet(ctx),
child: Container(
child: Icon(Icons.my_location, size: 28, color: Colors.red,), // FlutterLogo(),
),
),
);
markers.add(mark);
}
void _handleTap(LatLng latlng) {
}
void _configureModalBottomSheet(context) {
}
}
听起来很蠢,但是你在初始化地图控制器吗? 像 MapController mapController = MapController();