Flutter mapController LateInitializationError

问题描述 投票:0回答:1

我试图设置一个mapController来返回Flutter_map的边界,但是这个“LateInitializationError:Field '_internalController@'尚未初始化”错误不断出现

import 'package:flutter/material.dart';
import 'dart:io';
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
import 'package:dio_cache_interceptor_file_store/dio_cache_interceptor_file_store.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:flutter_map_cache/flutter_map_cache.dart';
import 'package:latlong2/latlong.dart';
import 'package:path_provider/path_provider.dart';

class CityMap extends StatefulWidget {
  const CityMap({super.key});

  @override
  State<CityMap> createState() => _CityMapState();
}

class _CityMapState extends State<CityMap> with TickerProviderStateMixin {
  final Future<CacheStore> _cacheStoreFuture = _getCacheStore();

  static Future<CacheStore> _getCacheStore() async {
    final dir = await getTemporaryDirectory();
    return FileCacheStore('${dir.path}${Platform.pathSeparator}MapTiles');
  }

   var _mapController = MapController();

  List<LatLng> markertram = [const LatLng(51.502762, -0.113125)];

  List<Marker> buildMarker() {

    List<Marker> markers = [];
    LatLngBounds bounder = _mapController.camera.visibleBounds;

    void createMarkers(
        List<LatLng> positions, String metroNumber, List<String> polyLineIds) {
      List<Marker> tramMarkers = positions.where((position) {
        return bounder.contains(position);
      }).map((position) {
        return Marker(
          width: 20.0,
          height: 20.0,
          point: position,
          rotate: true,
          alignment: Alignment.center,
          child: GestureDetector(
            onTap: () {},
            child: Tooltip(
              message: " Metro $metroNumber",
              child: const Icon(Icons.tram_outlined),
            ),
          ),
        );
      }).toList();
      markers.addAll(tramMarkers);
    }

    createMarkers(markertram, '2', ['tram2']);

    return markers;
  }

  @override
  void initState() {
    super.initState();
    _mapController = MapController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: FutureBuilder<CacheStore>(
            future: _cacheStoreFuture,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                final cacheStore = snapshot.data!;
                return Stack(
                  children: [
                    FlutterMap(
                      mapController: MapController(),
                      options: const MapOptions(
                        initialCenter: LatLng(51.515635, -0.092354),
                        initialZoom: 15.5,
                        maxZoom: 19.5,
                      ),
                      children: [
                        TileLayer(
                          urlTemplate:
                              'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
                              tileProvider: CachedTileProvider(
                        store: cacheStore,
                      ),
                        ),
                        MarkerLayer(
                          markers: buildMarker(),
                        ),
                      ],
                    ),
                  ],
                );
                
          } else if (snapshot.hasError) {
            return Center(child: Text(snapshot.error.toString()));
          }
          return const Center(child: CircularProgressIndicator());
        },
      ));
              }
            }

我所看到的解决方案似乎都是在 initstate 中设置 mapController,但这不起作用。但我也使用 futurebuilder 来延迟标记渲染

flutter dart
1个回答
0
投票

问题就像错误所说的那样,您在渲染

MapController
之前使用
FlutterMap
来管理
FlutterMap
。有一个错误可以修复:

  1. 您声明了
    _mapController
    ,但在
    MapController()
    小部件中使用了
    FlutterMap
FlutterMap(
  // Use [_mapController] instead of MapController.
  // 
  // So you can manage the map using [_mapController].
  mapController: _mapController,
  options: const MapOptions(
    initialCenter: LatLng(51.515635, -0.092354),
    initialZoom: 15.5,
    maxZoom: 19.5,
  ),
  children: [
    TileLayer(
      urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
      tileProvider: CachedTileProvider(
        store: cacheStore,
      ),
    ),
    MarkerLayer(
      markers: buildMarker(),
    ),
  ],
),
  1. buildMarker()
    内呼唤
    FlutterMap

这会导致错误,因为

FlutterMap
尚未渲染。
onMapReady
中有一个属性
MapOptions
提供了这种情况。我的建议是创建新变量:

List<Marker> _markersList = []

然后在您的

FlutterMap
选项中,在
_markerList
属性中填写
onMapReady
值:

options: MapOptions(
  initialCenter: const LatLng(51.502762, -0.113125),
  initialZoom: 15.5,
  maxZoom: 19.5,
  // This is where you can manage Map using _mapController for the first time rendered.
  //
  // Before use _mapController, make sure that FlutterMap is already rendered,
  // this [onMapReady] provided that case.
  onMapReady: () {
    // This is where the [_markers] value filled with [buildMarker()]
    // Then refresh the state using `setState` to effect.
    _markerList = buildMarker();
    setState(() {});
  },
),

通过这两个修复,您的应用程序将会很好。

我提供了额外的最小可重现代码供您尝试此解决方案,我根据您的代码进行了一些修改,但逻辑仍然相同。

import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';

class FlutterMapPage extends StatefulWidget {
  const FlutterMapPage({super.key});

  @override
  State<FlutterMapPage> createState() => _FlutterMapPageState();
}

class _FlutterMapPageState extends State<FlutterMapPage> {
  /// [mapController] use to programatically control the map camera & access
  /// some helper functionality - control camera.
  MapController mapController = MapController();

  /// Markers list on map
  List<Marker> _markers = [];

  Marker _buildMarker(LatLng position, String metroNumber) {
    const double markerSize = 20.0;

    Widget child = GestureDetector(
      onTap: () {},
      child: Tooltip(
        message: "Metro $metroNumber",
        child: const Icon(Icons.tram_outlined),
      ),
    );

    return Marker(
      width: markerSize,
      height: markerSize,
      point: position,
      rotate: true,
      alignment: Alignment.center,
      child: child,
    );
  }

  List<Marker> _getMarkerList() {
    // Initiate tram position
    const List<LatLng> tramsPosition = [LatLng(51.502762, -0.113125)];

    // Initiate metroNumber
    const String metroNumber = '2';

    // Initiate markers variable to store list of marker data in this function.
    final List<Marker> markers = [];

    // Initiate the map camera bounder position.
    final LatLngBounds bounder = mapController.camera.visibleBounds;

    // Get list of trams position inside [bounder].
    List<LatLng> tramInBounder = tramsPosition
        .where(
          (position) => bounder.contains(position),
        )
        .toList();

    // Iterate [tramInBounder] for add [tramInBounder] value to [markers]
    for (LatLng position in tramInBounder) {
      markers.add(_buildMarker(position, metroNumber));
    }

    return markers;
  }

  @override
  Widget build(BuildContext context) {
    const String urlTemplate = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';

    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Map')),
      body: FlutterMap(
        mapController: mapController,
        options: MapOptions(
          initialCenter: const LatLng(51.502762, -0.113125),
          initialZoom: 15.5,
          maxZoom: 19.5,
          // This is where you run a function with [_mapController].
          //
          // Before use _mapController, make sure that FlutterMap is already rendered,
          // this [onMapReady] provided that case.
          onMapReady: () {
            // This is where the [_markers] value filled with [buildMarker()]
            // Then refresh the state using `setState` to effect.
            _markers = _getMarkerList();
            setState(() {});
          },
        ),
        children: [
          TileLayer(urlTemplate: urlTemplate),
          MarkerLayer(markers: _markers),
        ],
      ),
    );
  }
}

输出

Output Flutter Map

© www.soinside.com 2019 - 2024. All rights reserved.