Я все еще новичок в Flutter / Dart, использую шаблон блока / репозитория flutter_bloc, и у меня странное поведение в моем приложении. Все распечатки показывают, что все потоки и шаблон блока работают правильно, входящие состояния несут координаты, а переменная, содержащая самые новые координаты, никогда не равна нулю, но при загрузке MapScreen она не рисует карту в координатах userLocation. Также при нажатии центральной кнопки иногда появляется The method 'move' was called on null.
ошибка.
В MapScreen userLocation
, который получает свое значение из входящего состояния
return BlocBuilder<MapBloc, MapState>(
// bloc: MapBloc(mapRepository: _mapRepository),
builder: (BuildContext context, MapState state) {
userLocation = (state as LocationStream).location;
// if (state is LocationStream) {
// userLocation = (state).location;
// }
return Scaffold(
затем используется для рисования карты в местоположении пользователя
child: FlutterMap(
options: MapOptions(
center: userLocation,
minZoom: 5.0,
maxZoom: 19.0,
),
mapController: _mapController,
для отображения пользователя на карте
Marker(
point: userLocation,
height: 200,
width: 200,
builder: (context) => IconButton(
icon: Icon(Icons.location_on),
color: Colors.red,
iconSize: 60,
onPressed: () {
print('icon tapped');
},
),
),
и центрировать карту относительно местоположения пользователя.
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
onPressed: () {
print(
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ userLocation is $userLocation');
_mapController.move(userLocation, 16);
},
color: Colors.red,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'center',
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
),
Странно то, что иногда, когда я нажимаю центральную кнопку, я получаю The method 'move' was called on null.
ошибку, но не всегда.
Иногда срабатывает каждый раз, когда я нажимаю на нее, но иногда она находит значение null после того, как несколько раз сработало.
При первой сборке центральная кнопка работает должным образом и центрирует карту, но всегда находит значение null после горячей перезагрузки или горячего перезапуска.
Вы видите, что я делаю не так? Большое спасибо за ваше время и помощь.
Полный код пользовательского интерфейса:
class MapScreen extends StatelessWidget {
final String name;
final MapRepository _mapRepository;
final MapController _mapController;
// final AlertRepository _alertRepository;
List<Marker> alerts;
LatLng userLocation;
MapScreen(
{Key key, @required this.name, @required MapRepository mapRepository})
: assert(mapRepository != null),
_mapRepository = mapRepository,
_mapController = MapController(),
// _alertRepository = alertRepository,
super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<MapBloc, MapState>(
// bloc: MapBloc(mapRepository: _mapRepository),
builder: (BuildContext context, MapState state) {
userLocation = (state as LocationStream).location;
// if (state is LocationStream) {
// userLocation = (state).location;
// }
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
title: Text(
'Home',
style: TextStyle(color: Colors.orangeAccent, fontSize: 40),
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.exit_to_app,
color: Colors.orange,
size: 35,
),
onPressed: () {
BlocProvider.of<AuthenticationBloc>(context).add(
LoggedOut(),
);
},
),
],
),
backgroundColor: Colors.white,
body: SafeArea(
minimum: EdgeInsets.symmetric(horizontal: 20),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 570,
width: 320,
child: FlutterMap(
options: MapOptions(
center: userLocation,
minZoom: 5.0,
maxZoom: 19.0,
),
mapController: _mapController,
layers: [
//
// PolygonLayer(polygonOpts, map, stream)
// PolygonLayerOptions(
// polygons:
// ),
TileLayerOptions(
urlTemplate:
'https://api.openrouteservice.org/mapsurfer/{z}/{x}/{y}.png?api_key=5b3ce3597851110001cf62484c4b65d85bc844eca3a2c6b9f300ddf4',
// urlTemplate:
// 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
keepBuffer: 20),
new MarkerLayerOptions(
markers: [
Marker(
point: userLocation,
height: 200,
width: 200,
builder: (context) => IconButton(
icon: Icon(Icons.location_on),
color: Colors.red,
iconSize: 60,
onPressed: () {
print('icon tapped');
},
),
),
// Marker(
// height: ,
// builder: BlocBuilder<AlertBloc,AlertState>(
// builder: (BuildContext context, AlertState state) {
// alerts = (state as AlertsUpdated).alerts;
// return
// }),
// )
],
),
],
),
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
onPressed: () {
print(
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ userLocation is $userLocation');
_mapController.move(userLocation, 16);
},
color: Colors.red,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'center',
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
),
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
onPressed: () {
//TODO this goes actually in a alert icon callbac, here just navigates icons vc
},
color: Colors.red,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'alert',
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
),
],
),
],
),
),
),
);
});
}
}
Я также собрал образец приложения на случай, если вы захотите взглянуть на него. https://github.com/vinnytwice/flutter_app
ОБНОВИТЬ:
Обнаружив, что FlutterMap должен быть в виджете с отслеживанием состояния, я изменил свой. Во входящем состоянии я выполнил проверку типа состояния и на стороне, которая вызвала setState () с новым значением из состояния. Ошибка .. Конструктор, который восстанавливает ошибку вида строительного виджета, если я правильно помню ошибку. .. BlocBuilder больше не был правильным выбором, поэтому я заменил его на BlocListener, у которого есть обратный вызов для состояний, и вызвал там setState (). FlutterMap теперь отрисовывается на userLocation на buttonPressed даже после Hot-reload или Hot-restart ... и больше не The method 'move' was called on null.
ошибок ... так что одна проблема решена.
По-прежнему FlutterMap не отображается на userLocation при загрузке экрана. Вы видите, что мне не хватает? Возможно, какие-то начальные координаты? В любом случае ... не следует ли setState () отслеживать, где используется userLocation, и перестраивать эти виджеты?
Если я вызываю _mapController.move (userLocation, 16); сразу после setState (), карта будет следовать за местоположением пользователя, что полезно в пошаговом навигаторе, но это не то, что мне нужно ... также, если вы панорамируете ее как как только появляется новое состояние, карта перемещается ..
Итак, новый код:
// stateful widget using BlocListener:
class MapScreen extends StatefulWidget {
final String name;
final MapRepository _mapRepository;
// MapController _mapController;
// final AlertRepository _alertRepository;
MapScreen(
{Key key, @required this.name, @required MapRepository mapRepository})
: assert(mapRepository != null),
_mapRepository = mapRepository,
// _mapController = MapController(),
// _alertRepository = alertRepository,
super(key: key);
@override
_MapScreenState createState() => _MapScreenState();
}
class _MapScreenState extends State<MapScreen> {
List<Marker> alerts;
LatLng userLocation;
MapController _mapController = MapController();
@override
Widget build(BuildContext context) {
return BlocListener<MapBloc, MapState>(
// bloc: MapBloc(mapRepository: _mapRepository),
listener: (BuildContext context, MapState state) {
// userLocation = (state as LocationStream).location;
if (state is LocationStream) {
setState(() {
userLocation = (state).location;
});
}
},
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
title: Text(
'Home',
style: TextStyle(color: Colors.orangeAccent, fontSize: 40),
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.exit_to_app,
color: Colors.orange,
size: 35,
),
onPressed: () {
// BlocProvider.of<AuthenticationBloc>(context).add(
// LoggedOut(),
// );
},
),
],
),
backgroundColor: Colors.white,
body: SafeArea(
minimum: EdgeInsets.symmetric(horizontal: 20),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
height: 570,
width: 320,
child: FlutterMap(
options: MapOptions(
center: userLocation,
minZoom: 5.0,
maxZoom: 19.0,
),
mapController: _mapController,
layers: [
//
// PolygonLayer(polygonOpts, map, stream)
// PolygonLayerOptions(
// polygons:
// ),
TileLayerOptions(
urlTemplate:
'https://api.openrouteservice.org/mapsurfer/{z}/{x}/{y}.png?api_key=5b3ce3597851110001cf62484c4b65d85bc844eca3a2c6b9f300ddf4',
// urlTemplate:
// 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c'],
keepBuffer: 20),
new MarkerLayerOptions(
markers: [
Marker(
point: userLocation,
height: 200,
width: 200,
builder: (context) => IconButton(
icon: Icon(Icons.location_on),
color: Colors.red,
iconSize: 60,
onPressed: () {
print('icon tapped');
},
),
),
// Marker(
// height: ,
// builder: BlocBuilder<AlertBloc,AlertState>(
// builder: (BuildContext context, AlertState state) {
// alerts = (state as AlertsUpdated).alerts;
// return
// }),
// )
],
),
],
),
),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
onPressed: () {
print(
' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ userLocation is $userLocation');
_mapController.move(userLocation, 16);
},
color: Colors.red,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'center',
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
),
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5)),
onPressed: () {
//TODO this goes actually in a alert icon callbac, here just navigates icons vc
},
color: Colors.red,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Text(
'alert',
style: TextStyle(color: Colors.white, fontSize: 30),
),
),
),
],
),
],
),
),
),
),
);
}
}
userLocation
при загрузке MapScreen. Кроме того, я не редактировал вопрос и не удалял старую часть, для которой нашел решение, но поместил ее в раздел ОБНОВЛЕНИЕ, чтобы она была полезна другим, показывая всю историю проблемы. - person Vincenzo   schedule 05.03.2020