- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试将谷歌地图集成到我的应用程序中,并为其提供源和目的地以放置标记。它从前几天运行正常,完全没有错误。今天突然出现此错误, 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/
我正在尝试从flutter应用程序构建apk,但出现此错误: Note: /mnt/Software/Linux/Flutter/flutter/.pub-cache/hosted/pub.dartl
我有一个名为 X 的较大应用程序,还有另一个名为 Y 的较小应用程序。他们现在彼此分开,并且工作正常。我想将应用程序 Y 集成到 X 中。我想将 Y 的代码放入 X 项目中,但它们应该有不同的 Mai
在android Studio中选择Create New Flutter Project,出现如下4个选项。 Flutter 应用程序 Flutter 插件 Flutter 包 flutter 模块
我看到我的 flutter 项目生成了一个文件 ios/Flutter/Flutter.podspec ,这个文件有什么用? 如果它与生成的 Flutter.framework 有关? 我应该将它包含
我尝试过的 在包含flutter SDK的位置添加/编辑.bash_profile.rtf文件。 导出PATH = / Users / temur / Documents / Projects / F
Flutter 日志会打印数千个详细/垃圾邮件日志。 我正在尝试调试一个复杂的应用程序,但是打印太冗长了,以至于我很难找到我自己打印的东西。 有没有办法禁用详细? 就像是: Logger.level.
在flutter 1.22更新之后,我在Lineargradient colors属性中遇到错误,这给我一个错误,即未定义名称colors参数。.在Android中更新flutter和flutter插
在下面的代码 widget.hintText 中给出错误,我试图将日期选择器作为单独的组件,并在从其他文件调用它时动态传递提示文本值。 import 'package:date_field/date_
在下面的代码 widget.hintText 中给出错误,我试图将日期选择器作为单独的组件,并在从其他文件调用它时动态传递提示文本值。 import 'package:date_field/date_
Flutter 1.0 发布后,我正在按照步骤搭建 Flutter 开发环境。 在步骤中(如所附屏幕截图所示),它说要更新 $PATH 两次,一次使用 flutter 工具的路径 export PAT
我有一个用 flutter 编写的移动应用程序,我想将其转换为 flutter_web 应用程序(集成 flutter_web 尚不可用)。我目前遇到包裹问题。 我已按照本网站中列出的说明进行操作 h
如何向我的 Flutter 路由添加自定义转换?这是我目前的路线结构。 class MyApp extends StatelessWidget { // This widget is the
我正在尝试通过 URL 在 webview 中显示网页。我试过 flutter_webview_plugin 插件,但是当我在浏览器上运行项目时它不起作用。 在 flutter web applica
我正在使用 animatedContainer 在按下按钮时显示 listView.builder()。这是一个要显示的简单子(monad)列表,但问题是我不知道 ListView 构建器的高度会传递
我目前正在我的应用程序中制作渐变背景动画......我正在使用 lottie 动画的帮助下这样做!我试图将它封装在一个容器中并成功地做到了。但是有一个问题,尽管我将高度更改为大于 2000 的东西,但
美好的一天! 我无法弄清楚如何使用 google 标签管理器设置 flutter。我找到了 this package包括标签管理器 api。但是我不知道如何正确配置它。 (在网络上我只需要复制粘贴一个
我的购物车模型如下 class Cart { String description; double unitCost; double amount; int quantity; S
在 Flutter 应用程序中,我想为在线托管的资源(图像、视频等)实现缓存。 我希望它能在原生平台 (Android/iOS)(例如使用文件系统)和网络(例如使用 IndexedDB)上运行。 Fl
我写了一个页面,在顶部一切都很好,应该是这样。在底部我有一个事件的历史。我的容器的宽度是自动确定的(取决于屏幕的宽度),而高度 - 不,在不同的设备上有不同的高度(底部的缩进是不同的)。是否可以自动确
我正在处理一个页面,其中有一些字段,例如 textfield 和 slider。在页面的末尾必须有一个用于进行下一步的按钮,该按钮被包裹在 Align 中以在页面之间具有固定位置。 另一方面,resi
我是一名优秀的程序员,十分优秀!