Files
feature-next-arch/lib/features/home/presentation/widgets/map/test_amap_page.dart

178 lines
5.0 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart';
import 'package:geolocator/geolocator.dart';
import 'package:permission_handler/permission_handler.dart';
import 'CoordTransform/coord_transform.dart';
class AmapFlutterMapPage extends StatefulWidget {
const AmapFlutterMapPage({super.key});
@override
State<AmapFlutterMapPage> createState() => _AmapFlutterMapPageState();
}
class _AmapFlutterMapPageState extends State<AmapFlutterMapPage> {
final MapController _mapController = MapController();
static const String amapKey = "bbb1f0f20eed6bf679eddf2625630aba";
LatLng _currentCenter = const LatLng(39.908823, 116.397470);
bool _isLoading = true;
// 新增:标记页面是否已销毁,防止异步操作访问已释放的控制器
bool _isDisposed = false;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_checkAndGetLocation();
});
}
// 新增:页面销毁时标记状态
@override
void dispose() {
_isDisposed = true; // 先标记销毁状态
// _mapController.dispose(); // 再销毁控制器
super.dispose();
}
Future<void> _checkAndGetLocation() async {
var status = await Permission.location.status;
if (status.isDenied) {
status = await Permission.location.request();
if (status.isDenied) {
if (!_isDisposed) { // 防护:页面没销毁才弹提示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('定位权限被拒绝,无法获取当前位置')),
);
setState(() { _isLoading = false; });
}
return;
}
}
if (status.isPermanentlyDenied) {
if (!_isDisposed) { // 防护:页面没销毁才弹提示
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('定位权限被永久拒绝,请去设置开启'),
action: SnackBarAction(label: '去设置', onPressed: openAppSettings),
),
);
setState(() { _isLoading = false; });
}
return;
}
await _getCurrentLocation();
}
Future<void> _getCurrentLocation() async {
if (_isDisposed) return;
setState(() { _isLoading = true; });
print('📍 开始定位...');
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
if (!_isDisposed) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('定位服务未启用,请开启定位服务')),
);
setState(() { _isLoading = false; });
}
return;
}
try {
final position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.bestForNavigation,
forceAndroidLocationManager: true,
timeLimit: const Duration(seconds: 8),
);
if (_isDisposed) return;
// ⭐⭐⭐ 关键修复点:WGS84 → GCJ02 ⭐⭐⭐
final gcjPoint = CoordTransform.wgs84ToGcj02(
position.latitude,
position.longitude,
);
setState(() {
_currentCenter = gcjPoint;
_isLoading = false;
});
if (!_isDisposed) {
_mapController.move(gcjPoint, 15.0);
}
print('✅ 定位成功(GCJ02): ${gcjPoint.latitude}, ${gcjPoint.longitude}');
} catch (e) {
if (!_isDisposed) {
setState(() { _isLoading = false; });
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('定位失败: $e'),
action: SnackBarAction(
label: '重试',
onPressed: _checkAndGetLocation,
),
),
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('路径规划'),
actions: [
IconButton(
icon: const Icon(Icons.my_location),
onPressed: _checkAndGetLocation,
tooltip: '定位到我的位置',
),
],
),
body: _isLoading
? const Center(child: CircularProgressIndicator())
: FlutterMap(
mapController: _mapController,
options: MapOptions(
center: _currentCenter,
zoom: 15.0,
minZoom: 3.0,
maxZoom: 18.0,
interactiveFlags: InteractiveFlag.all,
),
children: [
TileLayer(
urlTemplate:
"https://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}&key=$amapKey",
subdomains: const ['1', '2', '3', '4'],
tileProvider: NetworkTileProvider(),
),
MarkerLayer(
markers: [
Marker(
point: _currentCenter,
width: 40,
height: 40,
child: const Icon(Icons.location_on, color: Colors.red, size: 40),
),
],
),
],
),
);
}
}