gpt4 book ai didi

flutter - 延迟初始化错误 : Field 'mapController' has not been initialized

转载 作者:行者123 更新时间:2023-12-01 23:06:36 30 4
gpt4 key购买 nike

我正在尝试将谷歌地图集成到我的应用程序中,并为其提供源和目的地以放置标记。它从前几天运行正常,完全没有错误。今天突然出现此错误, map 无法正常工作。即使它没有在屏幕上显示谷歌地图,只是空白的白色屏幕。

class MapView extends StatefulWidget {
@override
_MapViewState createState() => _MapViewState();
}

class _MapViewState extends State<MapView> {
CameraPosition _initialLocation = CameraPosition(target: LatLng(0.0, 0.0));
**late GoogleMapController mapController ;**

late Position _currentPosition;
String _currentAddress = '';

final startAddressController = TextEditingController();
final destinationAddressController = TextEditingController();

final startAddressFocusNode = FocusNode();
final destinationAddressFocusNode = FocusNode();

String _startAddress = '';
String _destinationAddress = '';
double? _placeDistance;

Set<Marker> markers = {};

late PolylinePoints polylinePoints;
List<LatLng> polylineCoordinates = [];
Map<PolylineId, Polyline> polylines = {};

final _scaffoldKey = GlobalKey<ScaffoldState>();

Widget _textField({

required TextEditingController controller,
required FocusNode focusNode,
required String label,
required String hint,
required double width,
required Icon prefixIcon,
Widget? suffixIcon,
required Function(String) locationCallback,

}) {
return Container(

width: width * 0.8,
child: TextField(
onChanged: (value) {
locationCallback(value);
},
controller: controller,
focusNode: focusNode,
decoration: new InputDecoration(
prefixIcon: prefixIcon,
suffixIcon: suffixIcon,
labelText: label,
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
borderSide: BorderSide(
color: Colors.grey.shade400,
width: 2,
),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
borderSide: BorderSide(
color: Colors.blue.shade300,
width: 2,
),
),
contentPadding: EdgeInsets.all(15),
hintText: hint,
),
),
);
}

// Method for retrieving the current location
_getCurrentLocation() async {
await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high)
.then((Position position) async {
setState(() {
_currentPosition = position;
print('CURRENT POS: $_currentPosition');
**mapController.animateCamera(**
CameraUpdate.newCameraPosition(
CameraPosition(
target: LatLng(position.latitude, position.longitude),
zoom: 18.0,
),
),
);
});
await _getAddress();
}).catchError((e) {
print(e);
});
}

下一部分:

_getAddress() async {
try {
List<Placemark> p = await placemarkFromCoordinates(
_currentPosition.latitude, _currentPosition.longitude);

Placemark place = p[0];

setState(() {
_currentAddress =
"${place.name}, ${place.locality}, ${place.postalCode}, ${place.country}";
startAddressController.text = _currentAddress;
_startAddress = _currentAddress;
});
} catch (e) {
print(e);
}
}

// Method for calculating the distance between two places
Future<bool> _calculateDistance() async {
try {
// Retrieving placemarks from addresses
List<Location> startPlacemark = await locationFromAddress(_startAddress);
List<Location> destinationPlacemark =
await locationFromAddress(_destinationAddress);

// Use the retrieved coordinates of the current position,
// instead of the address if the start position is user's
// current position, as it results in better accuracy.
double startLatitude = _startAddress == _currentAddress
? _currentPosition.latitude
: startPlacemark[0].latitude;

double startLongitude = _startAddress == _currentAddress
? _currentPosition.longitude
: startPlacemark[0].longitude;

double destinationLatitude = destinationPlacemark[0].latitude;
double destinationLongitude = destinationPlacemark[0].longitude;

String startCoordinatesString = '($startLatitude, $startLongitude)';
String destinationCoordinatesString =
'($destinationLatitude, $destinationLongitude)';

// Start Location Marker
Marker startMarker = Marker(
markerId: MarkerId(startCoordinatesString),
position: LatLng(startLatitude, startLongitude),
infoWindow: InfoWindow(
title: 'Start $startCoordinatesString',
snippet: _startAddress,
),
icon: BitmapDescriptor.defaultMarker,
);

// Destination Location Marker
Marker destinationMarker = Marker(
markerId: MarkerId(destinationCoordinatesString),
position: LatLng(destinationLatitude, destinationLongitude),
infoWindow: InfoWindow(
title: 'Destination $destinationCoordinatesString',
snippet: _destinationAddress,
),
icon: BitmapDescriptor.defaultMarker,
);


// Adding the markers to the list
markers.add(startMarker);
markers.add(destinationMarker);

print(
'START COORDINATES: ($startLatitude, $startLongitude)',
);
print(
'DESTINATION COORDINATES: ($destinationLatitude, $destinationLongitude)',
);

// Calculating to check that the position relative
// to the frame, and pan & zoom the camera accordingly.
double miny = (startLatitude <= destinationLatitude)
? startLatitude
: destinationLatitude;
double minx = (startLongitude <= destinationLongitude)
? startLongitude
: destinationLongitude;
double maxy = (startLatitude <= destinationLatitude)
? destinationLatitude
: startLatitude;
double maxx = (startLongitude <= destinationLongitude)
? destinationLongitude
: startLongitude;

double southWestLatitude = miny;
double southWestLongitude = minx;

double northEastLatitude = maxy;
double northEastLongitude = maxx;

// Accommodate the two locations within the
// camera view of the map
mapController.animateCamera(
CameraUpdate.newLatLngBounds(
LatLngBounds(
northeast: LatLng(northEastLatitude, northEastLongitude),
southwest: LatLng(southWestLatitude, southWestLongitude),
),
100.0,
),
);

// Calculating the distance between the start and the end positions
// with a straight path, without considering any route
// double distanceInMeters = await Geolocator.bearingBetween(
// startLatitude,
// startLongitude,
// destinationLatitude,
// destinationLongitude,
// );

await _createPolylines(startLatitude, startLongitude, destinationLatitude,
destinationLongitude);

double totalDistance = 0.0;

// Calculating the total distance by adding the distance
// between small segments
for (int i = 0; i < polylineCoordinates.length - 1; i++) {
totalDistance += _coordinateDistance(

polylineCoordinates[i].latitude,
polylineCoordinates[i].longitude,
polylineCoordinates[i + 1].latitude,
polylineCoordinates[i + 1].longitude,

);
}

setState(() {
_placeDistance = totalDistance;
print('DISTANCE: $_placeDistance km');
});

return true;
} catch (e) {
print(e);
}
return false;
}



// Formula for calculating distance between two coordinates
// https://stackoverflow.com/a/54138876/11910277
double _coordinateDistance(lat1, lon1, lat2, lon2) {
var p = 0.017453292519943295;
var c = cos;
var a = 0.5 -
c((lat2 - lat1) * p) / 2 +
c(lat1 * p) * c(lat2 * p) * (1 - c((lon2 - lon1) * p)) / 2;
return 12742 * asin(sqrt(a));
}

// Create the polylines for showing the route between two places
_createPolylines(

double startLatitude,
double startLongitude,
double destinationLatitude,
double destinationLongitude,
) async {


polylinePoints = PolylinePoints();
PolylineResult result = await polylinePoints.getRouteBetweenCoordinates(
Secrets.API_KEY, // Google Maps API Key
PointLatLng(startLatitude, startLongitude),
PointLatLng(destinationLatitude, destinationLongitude),
travelMode: TravelMode.driving,

);

result.points.forEach((PointLatLng point) {
polylineCoordinates.add(LatLng(point.latitude, point.longitude));

ScaffoldMessenger.of(context)
.showSnackBar(
SnackBar(
content: Text(
'Poly here'),
),
);
});




PolylineId id = PolylineId('poly');
Polyline polyline = Polyline(
polylineId: id,
color: Colors.red,
points: polylineCoordinates,
width: 3,
);
polylines[id] = polyline;
setState(() {});
}



@override
void initState() {
super.initState();
_getCurrentLocation();
_calculateDistance();
}
@override
void dispose() {
mapController.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return Container(
height: height,
width: width,
child: Scaffold(
key: _scaffoldKey,
body: Stack(
children: <Widget>[
// Map View
GoogleMap(
markers: Set<Marker>.from(markers),
initialCameraPosition: _initialLocation,
myLocationEnabled: true,
myLocationButtonEnabled: false,
mapType: MapType.normal,
zoomGesturesEnabled: true,
zoomControlsEnabled: false,
polylines: Set<Polyline>.of(polylines.values),
onMapCreated: (GoogleMapController controller) {
setState(() {
mapCreated = true;
});

mapController = controller;
},
),
// Show zoom buttons
SafeArea(
child: Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ClipOval(
child: Material(
color: Colors.blue.shade100, // button color
child: InkWell(
splashColor: Colors.blue, // inkwell color
child: SizedBox(
width: 50,
height: 50,
child: Icon(Icons.add),
),
onTap: () {
mapController.animateCamera(
CameraUpdate.zoomIn(),
);
},
),
),
),

最佳答案

当您像这样创建 GoogleMap 小部件时,您必须存储 GoogleMapController:

GoogleMap(
onMapCreated: (GoogleMapController controller) {
// here save the value
mapController = controller;
}

您必须确保此 onMapCreated 在您尝试访问您的 mapController 之前运行(例如使用 FutureBuilder),否则您将不断收到此错误消息。另一种选择是删除 late 关键字,允许成员为空,并在使用前检查空值。

此外,不要忘记妥善处理 Controller :

@override
void dispose() {
mapController.dispose();
super.dispose();
}

在您的代码中,您从 initState 调用 _getCurrentLocation async 函数。这通常不是一个好的方法,因为 initState 不可能是一个 async 函数,所以没有办法使用 await 来确保这些功能在您的小部件首次构建之前完成。

但在这种情况下,最大的问题是只有在创建了 GoogleMap 小部件之后,您才会拥有一个有效的 GoogleMapController。这就是 onMapCreated 的主要用途,即在创建 map 后获取 GoogleMapController

并且由于在 _getCurrentLocation 中您尝试访问 mapController,它还不可用,因为它可能在 GoogleMap 之前执行已创建。

现在,_getCurrentLocation 使用 await 获取当前位置,完成后,它会尝试调用 mapController.animateCamera。这就是为什么您可以更早体验到它有效的原因。这是一个典型的赛车问题。如果 Geolocator.getCurrentPosition 花费了足够的时间,则 GoogleMap 可能已经构建,因此您有一个有效的 GoogleMapController。但是您不能确定,正如您当前的错误所示,这取决于获得当前职位需要多长时间。

解决方案是什么?您必须重新组织代码,以便仅在创建 GoogleMap 后才使用 mapController。例如,将您的 _getCurrentLocation 函数调用从 initState 移动到 onMapCreated,这样您就可以确保拥有一个有效的 map Controller 。但是请确保在 mapController 可用之前没有任何代码依赖它。

下面是一些代码,展示了如何完成这项工作:

class MyPageHomeMap extends StatefulWidget {
const MyPageHomeMap({Key? key}) : super(key: key);

@override
State<MyPageHomeMap> createState() => _MyPageHomeMapState();
}

class _MyPageHomeMapState extends State<MyPageHomeMap> {

bool _mapCreated = false;
late GoogleMapController mapController;


@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
GoogleMap(
initialCameraPosition: <something>,
onMapCreated: _onMapCreated),
if (!_mapCreated) const Center(child: CircularProgressIndicator())
],
),
);
}

_onMapCreated(GoogleMapController controller) {
mapController = controller;
setState(() {
_mapCreated = true;
});
// get current position here and use mapController when it is completed
}
}

关于flutter - 延迟初始化错误 : Field 'mapController' has not been initialized,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70755616/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com