Я все еще очень плохо знаком с Flutter / Dart и использую шаблон flutter_blo c bloc / repository, и в моем приложении наблюдается странное поведение. Все распечатки показывают, что все потоки и шаблон blo c работают правильно, входящие состояния содержат координаты, а переменная, в которой хранятся новейшие координаты, никогда не равна нулю, но при загрузке 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 должен быть в виджете с состоянием, я изменил свой. При входящем состоянии я выполнил проверку типа State и в стороне, которая вызвала setState () с новым значением из состояния. Ошибка .. Строитель, который перестраивает вид ошибки при создании виджета, если я правильно помню ошибку. .. BlocBuilder больше не был правильным выбором, поэтому я поменял его на BlocListener, который имеет обратный вызов состояний и вызвал там setState (). FlutterMap теперь отображается в userLocation на buttonPressed даже после горячей перезагрузки или горячего перезапуска ... и не более 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),
),
),
),
],
),
],
),
),
),
),
);
}
}