Карта не отображается на месте пользователя при загрузке экрана - PullRequest
0 голосов
/ 04 марта 2020

Я все еще очень плохо знаком с 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),
                        ),
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
} 

1 Ответ

0 голосов
/ 06 марта 2020

Я наконец заставил это работать. Я закончил тем, что использовал подход, который, думая, что с Stream<LatLng> userLocation я бы отсортировался, я отложил на неделю go, потому что я еще не знал, как правильно использовать Futures.

В репозитории я использую метод, который просто возвращает Future<LatLng>:

Future<LatLng> getLocation() async {
    print('getLocation() called');
    Position position;
    LatLng location;
    try {
      position = await locationManager
          .getCurrentPosition(
              desiredAccuracy: LocationAccuracy.bestForNavigation)
          .timeout(Duration(seconds: 5));
      location = LatLng(position.latitude, position.longitude);
      print('getLocation() location is: $location');
      return location;
    } catch (error) {
      print(
          'getLocation(): error getting current location: ${error.toString()}');
    }
  }

From BlocProvider in main() Теперь я отправляю два события:

BlocProvider<MapBloc>(create: (context) {
          return MapBloc(
            mapRepository: mapRepository,
          )
            ..add(GetLocationStream())
            ..add(GetInitialLocation());
        }),

In blo c получить состояние со значением из `getLocation ().

Stream<MapState> _mapCenterMapToState(GetInitialLocation event) async* {
    location = await _mapRepository.getLocation();
    print('_mapCenterMapToState location is : ${_mapRepository.getLocation()}');
    yield MapLoading(location);
  } 

В BlocListener Я добавил новую проверку состояния и использовал значение состояния для перемещения карты.

BlocListener<MapBloc, MapState>(
            listener: (BuildContext context, MapState state) {
          if (state is LocationStream) {
            setState(() {
              userLocation = (state).location;
            });
          }
          if (state is MapLoading) {
            userLocation = (state).location;
            print(
                ' @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ MapBloc initial state location is : $userLocation');
            _mapController.move(userLocation, 16);
          }
        })

Карта теперь загружается в местоположении пользователя, но не перемещается вместе с ней, значок местоположения пользователя постоянно обновляется, а центральная кнопка при нажатии центрирует карту в местоположении пользователя.

Надеюсь, этот длинный вопрос и ответ помогут другим просто начиная как я. Приветствия.

...