init project
This commit is contained in:
9
example/lib/base_page.dart
Normal file
9
example/lib/base_page.dart
Normal file
@ -0,0 +1,9 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
///demo的模板类
|
||||
abstract class BasePage extends StatelessWidget {
|
||||
final String title;
|
||||
final String subTitle;
|
||||
|
||||
const BasePage(this.title, this.subTitle);
|
||||
}
|
9
example/lib/const_config.dart
Normal file
9
example/lib/const_config.dart
Normal file
@ -0,0 +1,9 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
|
||||
class ConstConfig {
|
||||
static const AMapApiKey amapApiKeys = AMapApiKey(
|
||||
androidKey: '900f72eeee0f21e435cebb0ef155582a',
|
||||
iosKey: '4dfdec97b7bf0b8c13e94777103015a9');
|
||||
static const AMapPrivacyStatement amapPrivacyStatement =
|
||||
AMapPrivacyStatement(hasContains: true, hasShow: true, hasAgree: true);
|
||||
}
|
136
example/lib/main.dart
Normal file
136
example/lib/main.dart
Normal file
@ -0,0 +1,136 @@
|
||||
import 'package:amap_map_example/pages/overlays/marker_add_after_map.dart';
|
||||
import 'package:amap_map_example/pages/overlays/marker_add_with_map.dart';
|
||||
import 'package:amap_map_example/pages/overlays/marker_config.dart';
|
||||
import 'package:amap_map_example/pages/overlays/marker_custom_icon.dart';
|
||||
import 'package:amap_map_example/pages/overlays/place_polygon.dart';
|
||||
import 'package:amap_map_example/pages/overlays/place_polyline.dart';
|
||||
import 'package:amap_map_example/pages/interactive/map_gestures_options.dart';
|
||||
import 'package:amap_map_example/pages/interactive/map_ui_options.dart';
|
||||
import 'package:amap_map_example/pages/interactive/move_camera_demo.dart';
|
||||
import 'package:amap_map_example/pages/interactive/poi_click_demo.dart';
|
||||
import 'package:amap_map_example/pages/interactive/snapshot_demo.dart';
|
||||
import 'package:amap_map_example/pages/map/change_map_type.dart';
|
||||
import 'package:amap_map_example/pages/map/custom_map_style.dart';
|
||||
import 'package:amap_map_example/pages/map/limit_map_bounds.dart';
|
||||
import 'package:amap_map_example/pages/map/map_all_config.dart';
|
||||
import 'package:amap_map_example/pages/map/map_my_location.dart';
|
||||
import 'package:amap_map_example/pages/map/min_max_zoom.dart';
|
||||
import 'package:amap_map_example/pages/map/multi_map.dart';
|
||||
import 'package:amap_map_example/pages/map/show_map_page.dart';
|
||||
import 'package:amap_map_example/pages/overlays/polyline_geodesic.dart';
|
||||
import 'package:amap_map_example/pages/overlays/polyline_texture.dart';
|
||||
import 'package:amap_map_example/widgets/demo_group.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
import 'base_page.dart';
|
||||
|
||||
final List<BasePage> _mapDemoPages = <BasePage>[
|
||||
AllMapConfigDemoPage('总体演示', '演示AMapWidget的所有配置项'),
|
||||
ShowMapPage('显示地图', '基本地图显示'),
|
||||
LimitMapBoundsPage('限制地图显示范围', '演示限定手机屏幕显示地图的范围'),
|
||||
MinMaxZoomDemoPage('指定显示级别范围', '演示指定最小最大级别功能'),
|
||||
ChangeMapTypePage('切换地图图层', '演示内置的地图图层'),
|
||||
CustomMapStylePage('自定义地图', '根据自定义的地图样式文件显示地图'),
|
||||
MultiMapDemoPage('地图多实例', '同时显示多个地图'),
|
||||
];
|
||||
|
||||
final List<BasePage> _interactiveDemoPages = <BasePage>[
|
||||
MapUIDemoPage('UI控制', 'ui开关演示'),
|
||||
GesturesDemoPage('手势交互', '手势交互'),
|
||||
PoiClickDemoPage('点击poi功能', '演示点击poi之后的回调和信息透出'),
|
||||
MoveCameraDemoPage('改变地图视角', '演示改变地图的中心点、可视区域、缩放级别等功能'),
|
||||
SnapshotPage('地图截屏', '地图截屏示例'),
|
||||
MyLocationPage('显示我的位置', '在地图上显示我的位置'),
|
||||
];
|
||||
|
||||
final List<BasePage> _markerPages = <BasePage>[
|
||||
MarkerConfigDemoPage('Marker操作', '演示Marker的相关属性的操作'),
|
||||
MarkerAddWithMapPage("随地图添加", "演示初始化地图时直接添加marker"),
|
||||
MarkerAddAfterMapPage("单独添加", "演示地图初始化之后单独添加marker功能"),
|
||||
MarkerCustomIconPage('自定义图标', '演示marker使用自定义图标功能'),
|
||||
];
|
||||
|
||||
final List<BasePage> _overlayPages = <BasePage>[
|
||||
PolylineDemoPage('Polyline操作', '演示Polyline的相关属性的操作'),
|
||||
PolylineGeodesicDemoPage('Polyline大地曲线', '演示大地曲线的添加'),
|
||||
PolylineTextureDemoPage('Polyline纹理线', '演示纹理线的添加'),
|
||||
PolygonDemoPage('Polygon操作', '演示Polygon的相关属性的操作'),
|
||||
];
|
||||
|
||||
final List<Permission> needPermissionList = [
|
||||
Permission.location,
|
||||
Permission.storage,
|
||||
Permission.phone,
|
||||
];
|
||||
|
||||
class AMapDemo extends StatefulWidget {
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return DemoWidget();
|
||||
}
|
||||
}
|
||||
|
||||
class DemoWidget extends State<AMapDemo> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_checkPermissions();
|
||||
}
|
||||
|
||||
@override
|
||||
void reassemble() {
|
||||
super.reassemble();
|
||||
_checkPermissions();
|
||||
}
|
||||
|
||||
void _checkPermissions() async {
|
||||
Map<Permission, PermissionStatus> statuses =
|
||||
await needPermissionList.request();
|
||||
statuses.forEach((key, value) {
|
||||
print('$key premissionStatus is $value');
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('高德地图示例')),
|
||||
body: Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: SingleChildScrollView(
|
||||
child: Container(
|
||||
child: Column(
|
||||
children: [
|
||||
DemoGroupWidget(
|
||||
groupLabel: '创建地图',
|
||||
itemPages: _mapDemoPages,
|
||||
),
|
||||
DemoGroupWidget(
|
||||
groupLabel: '地图交互',
|
||||
itemPages: _interactiveDemoPages,
|
||||
),
|
||||
DemoGroupWidget(
|
||||
groupLabel: '绘制点标记',
|
||||
itemPages: _markerPages,
|
||||
),
|
||||
DemoGroupWidget(
|
||||
groupLabel: '绘制线和面',
|
||||
itemPages: _overlayPages,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// debugProfileBuildsEnabled = true;
|
||||
// debugProfilePaintsEnabled = true;
|
||||
// debugPaintLayerBordersEnabled = true;
|
||||
runApp(MaterialApp(home: AMapDemo()));
|
||||
}
|
14
example/lib/page.dart
Normal file
14
example/lib/page.dart
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// ignore_for_file: public_member_api_docs
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
abstract class AMapExampleAppPage extends StatelessWidget {
|
||||
const AMapExampleAppPage(this.leading, this.title);
|
||||
|
||||
final Widget leading;
|
||||
final String title;
|
||||
}
|
123
example/lib/pages/interactive/map_gestures_options.dart
Normal file
123
example/lib/pages/interactive/map_gestures_options.dart
Normal file
@ -0,0 +1,123 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:amap_map_example/widgets/amap_gridview.dart';
|
||||
import 'package:amap_map_example/widgets/amap_switch_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class GesturesDemoPage extends BasePage {
|
||||
GesturesDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
_Body({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
///是否支持缩放手势
|
||||
bool _zoomGesturesEnabled = true;
|
||||
|
||||
///是否支持滑动手势
|
||||
bool _scrollGesturesEnabled = true;
|
||||
|
||||
///是否支持旋转手势
|
||||
bool _rotateGesturesEnabled = true;
|
||||
|
||||
///是否支持倾斜手势
|
||||
bool _tiltGesturesEnabled = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget map = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
rotateGesturesEnabled: _rotateGesturesEnabled,
|
||||
scrollGesturesEnabled: _scrollGesturesEnabled,
|
||||
tiltGesturesEnabled: _tiltGesturesEnabled,
|
||||
zoomGesturesEnabled: _zoomGesturesEnabled,
|
||||
);
|
||||
|
||||
//手势开关
|
||||
final List<Widget> gesturesOptions = [
|
||||
AMapSwitchButton(
|
||||
label: Text('旋转'),
|
||||
defaultValue: _rotateGesturesEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_rotateGesturesEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('滑动'),
|
||||
defaultValue: _scrollGesturesEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_scrollGesturesEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('倾斜'),
|
||||
defaultValue: _tiltGesturesEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_tiltGesturesEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('缩放'),
|
||||
defaultValue: _zoomGesturesEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_zoomGesturesEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
];
|
||||
Widget _gesturesOptiosWeidget() {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('手势控制', style: TextStyle(fontWeight: FontWeight.w600)),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: AMapGradView(childrenWidgets: gesturesOptions),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height * 0.6,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Container(
|
||||
child: _gesturesOptiosWeidget(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
138
example/lib/pages/interactive/map_ui_options.dart
Normal file
138
example/lib/pages/interactive/map_ui_options.dart
Normal file
@ -0,0 +1,138 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:amap_map_example/widgets/amap_gridview.dart';
|
||||
import 'package:amap_map_example/widgets/amap_switch_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MapUIDemoPage extends BasePage {
|
||||
MapUIDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
_Body({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
///显示路况开关
|
||||
bool _trafficEnabled = false;
|
||||
|
||||
///是否显示3D建筑物
|
||||
bool _buildingsEnabled = true;
|
||||
|
||||
///是否显示底图文字标注
|
||||
bool _labelsEnabled = true;
|
||||
|
||||
///是否显示指南针
|
||||
bool _compassEnabled = false;
|
||||
|
||||
///是否显示比例尺
|
||||
bool _scaleEnabled = true;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget map = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
trafficEnabled: _trafficEnabled,
|
||||
buildingsEnabled: _buildingsEnabled,
|
||||
compassEnabled: _compassEnabled,
|
||||
labelsEnabled: _labelsEnabled,
|
||||
scaleEnabled: _scaleEnabled,
|
||||
);
|
||||
|
||||
//ui控制
|
||||
final List<Widget> _uiOptions = [
|
||||
AMapSwitchButton(
|
||||
label: Text('显示路况'),
|
||||
defaultValue: _trafficEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_trafficEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示3D建筑物'),
|
||||
defaultValue: _buildingsEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_buildingsEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示指南针'),
|
||||
defaultValue: _compassEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_compassEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示地图文字'),
|
||||
defaultValue: _labelsEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_labelsEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示比例尺'),
|
||||
defaultValue: _scaleEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_scaleEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
Widget _uiOptionsWidget() {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('UI操作', style: TextStyle(fontWeight: FontWeight.w600)),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: AMapGradView(childrenWidgets: _uiOptions),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height * 0.7,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Container(
|
||||
child: _uiOptionsWidget(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
236
example/lib/pages/interactive/move_camera_demo.dart
Normal file
236
example/lib/pages/interactive/move_camera_demo.dart
Normal file
@ -0,0 +1,236 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:amap_map_example/widgets/amap_gridview.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MoveCameraDemoPage extends BasePage {
|
||||
MoveCameraDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
_Body({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
AMapController? _mapController;
|
||||
String? _currentZoom;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget amap = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
onMapCreated: _onMapCreated,
|
||||
onCameraMove: _onCameraMove,
|
||||
onCameraMoveEnd: _onCameraMoveEnd,
|
||||
);
|
||||
List<Widget> _optionsWidget = [
|
||||
_createMyFloatButton('改变显示区域', _changeLatLngBounds),
|
||||
_createMyFloatButton('改变中心点', _changeCameraPosition),
|
||||
_createMyFloatButton('改变缩放级别到18', _changeCameraZoom),
|
||||
_createMyFloatButton('按照像素移动地图', _scrollBy),
|
||||
];
|
||||
|
||||
Widget _cameraOptions() {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
child: AMapGradView(
|
||||
childrenWidgets: _optionsWidget,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints.expand(),
|
||||
child: Column(
|
||||
children: [
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minWidth: MediaQuery.of(context).size.width,
|
||||
minHeight: MediaQuery.of(context).size.height * 0.7),
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height * 0.7,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: amap,
|
||||
),
|
||||
Positioned(
|
||||
right: 5,
|
||||
bottom: 5,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
InkResponse(
|
||||
child: Container(
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
width: 40,
|
||||
height: 40,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onTap: _zoomIn,
|
||||
),
|
||||
InkResponse(
|
||||
child: Container(
|
||||
child: Icon(
|
||||
Icons.remove,
|
||||
color: Colors.white,
|
||||
),
|
||||
color: Colors.blue,
|
||||
width: 40,
|
||||
height: 40,
|
||||
),
|
||||
onTap: _zoomOut,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
_currentZoom != null
|
||||
? Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
color: Colors.grey,
|
||||
padding: EdgeInsets.all(5),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
_currentZoom!,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
)
|
||||
: SizedBox(),
|
||||
Container(
|
||||
child: _cameraOptions(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
|
||||
void _onMapCreated(AMapController controller) {
|
||||
setState(() {
|
||||
_mapController = controller;
|
||||
});
|
||||
}
|
||||
|
||||
//移动视野
|
||||
void _onCameraMove(CameraPosition cameraPosition) {}
|
||||
|
||||
//移动地图结束
|
||||
void _onCameraMoveEnd(CameraPosition cameraPosition) {
|
||||
setState(() {
|
||||
_currentZoom = '当前缩放级别:${cameraPosition.zoom}';
|
||||
});
|
||||
}
|
||||
|
||||
void _changeCameraPosition() {
|
||||
_mapController?.moveCamera(
|
||||
CameraUpdate.newCameraPosition(
|
||||
CameraPosition(
|
||||
//中心点
|
||||
target: LatLng(31.230378, 121.473658),
|
||||
//缩放级别
|
||||
zoom: 13,
|
||||
//俯仰角0°~45°(垂直与地图时为0)
|
||||
tilt: 30,
|
||||
//偏航角 0~360° (正北方为0)
|
||||
bearing: 0),
|
||||
),
|
||||
animated: true,
|
||||
);
|
||||
}
|
||||
|
||||
//改变显示级别
|
||||
void _changeCameraZoom() {
|
||||
_mapController?.moveCamera(
|
||||
CameraUpdate.zoomTo(18),
|
||||
animated: true,
|
||||
);
|
||||
}
|
||||
|
||||
//级别加1
|
||||
void _zoomIn() {
|
||||
_mapController?.moveCamera(
|
||||
CameraUpdate.zoomIn(),
|
||||
animated: true,
|
||||
);
|
||||
}
|
||||
|
||||
//级别减1
|
||||
void _zoomOut() {
|
||||
_mapController?.moveCamera(
|
||||
CameraUpdate.zoomOut(),
|
||||
animated: true,
|
||||
);
|
||||
}
|
||||
|
||||
//改变显示区域
|
||||
void _changeLatLngBounds() {
|
||||
_mapController?.moveCamera(
|
||||
CameraUpdate.newLatLngBounds(
|
||||
LatLngBounds(
|
||||
southwest: LatLng(33.789925, 104.838326),
|
||||
northeast: LatLng(38.740688, 114.647472)),
|
||||
15.0),
|
||||
animated: true,
|
||||
);
|
||||
}
|
||||
|
||||
//按照像素移动
|
||||
void _scrollBy() {
|
||||
_mapController?.moveCamera(
|
||||
CameraUpdate.scrollBy(50, 50),
|
||||
animated: true,
|
||||
duration: 1000,
|
||||
);
|
||||
}
|
||||
|
||||
TextButton _createMyFloatButton(String label, VoidCallback onPressed) {
|
||||
return TextButton(
|
||||
onPressed: onPressed,
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStateProperty.all(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
|
||||
//文字颜色
|
||||
foregroundColor: MaterialStateProperty.all(Colors.white),
|
||||
//水波纹颜色
|
||||
overlayColor: MaterialStateProperty.all(Colors.blueAccent),
|
||||
//背景颜色
|
||||
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||
//设置按下时的背景颜色
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return Colors.blueAccent;
|
||||
}
|
||||
//默认背景颜色
|
||||
return Colors.blue;
|
||||
}),
|
||||
),
|
||||
child: Text(label),
|
||||
);
|
||||
}
|
||||
}
|
69
example/lib/pages/interactive/poi_click_demo.dart
Normal file
69
example/lib/pages/interactive/poi_click_demo.dart
Normal file
@ -0,0 +1,69 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PoiClickDemoPage extends BasePage {
|
||||
PoiClickDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
_Body({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
Widget? _poiInfo;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget amap = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
touchPoiEnabled: true,
|
||||
onPoiTouched: _onPoiTouched,
|
||||
);
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints.expand(),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: amap,
|
||||
),
|
||||
Positioned(
|
||||
top: 40,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
height: 50,
|
||||
child: Container(
|
||||
child: _poiInfo,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget showPoiInfo(AMapPoi poi) {
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
color: Color(0x8200CCFF),
|
||||
child: Text(
|
||||
'您点击了 ${poi.name}',
|
||||
style: TextStyle(fontWeight: FontWeight.w600),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onPoiTouched(AMapPoi poi) {
|
||||
setState(() {
|
||||
_poiInfo = showPoiInfo(poi);
|
||||
});
|
||||
}
|
||||
}
|
85
example/lib/pages/interactive/snapshot_demo.dart
Normal file
85
example/lib/pages/interactive/snapshot_demo.dart
Normal file
@ -0,0 +1,85 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SnapshotPage extends BasePage {
|
||||
SnapshotPage(String title, String subTitle) : super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _SnapShotBody();
|
||||
}
|
||||
}
|
||||
|
||||
class _SnapShotBody extends StatefulWidget {
|
||||
@override
|
||||
State<StatefulWidget> createState() => _SnapShotState();
|
||||
}
|
||||
|
||||
class _SnapShotState extends State<_SnapShotBody> {
|
||||
AMapController? _mapController;
|
||||
Uint8List? _imageBytes;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
onMapCreated: _onMapCreated,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10, bottom: 10),
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
width: 100,
|
||||
child: TextButton(
|
||||
child: Text('截屏'),
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStateProperty.all(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10))),
|
||||
//文字颜色
|
||||
foregroundColor: MaterialStateProperty.all(Colors.white),
|
||||
//水波纹颜色
|
||||
overlayColor: MaterialStateProperty.all(Colors.blueAccent),
|
||||
//背景颜色
|
||||
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||
//设置按下时的背景颜色
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return Colors.blueAccent;
|
||||
}
|
||||
//默认背景颜色
|
||||
return Colors.blue;
|
||||
}),
|
||||
),
|
||||
onPressed: () async {
|
||||
final imageBytes = await _mapController?.takeSnapshot();
|
||||
setState(() {
|
||||
_imageBytes = imageBytes;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(color: Colors.blueGrey[50]),
|
||||
child: _imageBytes != null ? Image.memory(_imageBytes!) : null,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_onMapCreated(AMapController controller) {
|
||||
_mapController = controller;
|
||||
}
|
||||
}
|
78
example/lib/pages/map/change_map_type.dart
Normal file
78
example/lib/pages/map/change_map_type.dart
Normal file
@ -0,0 +1,78 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:amap_map_example/widgets/amap_radio_group.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ChangeMapTypePage extends BasePage {
|
||||
ChangeMapTypePage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _PageBody();
|
||||
}
|
||||
|
||||
class _PageBody extends StatefulWidget {
|
||||
_PageBody({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_PageBodyState createState() => _PageBodyState();
|
||||
}
|
||||
|
||||
class _PageBodyState extends State<_PageBody> {
|
||||
//地图类型
|
||||
late MapType _mapType;
|
||||
final Map<String, MapType> _radioValueMap = {
|
||||
'普通地图': MapType.normal,
|
||||
'卫星地图': MapType.satellite,
|
||||
'导航地图': MapType.navi,
|
||||
'公交地图': MapType.bus,
|
||||
'黑夜模式': MapType.night,
|
||||
};
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_mapType = MapType.normal;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
//创建地图
|
||||
final AMapWidget map = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
//地图类型属性
|
||||
mapType: _mapType,
|
||||
);
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height * 0.6,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Container(
|
||||
child: AMapRadioGroup(
|
||||
groupLabel: '地图样式',
|
||||
groupValue: _mapType,
|
||||
radioValueMap: _radioValueMap,
|
||||
onChanged: (value) => {
|
||||
//改变当前地图样式为选中的样式
|
||||
setState(() {
|
||||
_mapType = value as MapType;
|
||||
})
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
94
example/lib/pages/map/custom_map_style.dart
Normal file
94
example/lib/pages/map/custom_map_style.dart
Normal file
@ -0,0 +1,94 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:amap_map_example/widgets/amap_switch_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class CustomMapStylePage extends BasePage {
|
||||
CustomMapStylePage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _CustomMapStyleBody();
|
||||
}
|
||||
|
||||
class _CustomMapStyleBody extends StatefulWidget {
|
||||
_CustomMapStyleBody({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_CustomMapStyleState createState() => _CustomMapStyleState();
|
||||
}
|
||||
|
||||
class _CustomMapStyleState extends State<_CustomMapStyleBody> {
|
||||
bool _mapCreated = false;
|
||||
|
||||
CustomStyleOptions _customStyleOptions = CustomStyleOptions(false);
|
||||
//加载自定义地图样式
|
||||
void _loadCustomData() async {
|
||||
ByteData styleByteData = await rootBundle.load('assets/style.data');
|
||||
_customStyleOptions.styleData = styleByteData.buffer.asUint8List();
|
||||
ByteData styleExtraByteData =
|
||||
await rootBundle.load('assets/style_extra.data');
|
||||
_customStyleOptions.styleExtraData =
|
||||
styleExtraByteData.buffer.asUint8List();
|
||||
//如果需要加载完成后直接展示自定义地图,可以通过setState修改CustomStyleOptions的enable为true
|
||||
// setState(() {
|
||||
// _customStyleOptions.enabled = true;
|
||||
// });
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadCustomData();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget map = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
onMapCreated: onMapCreated,
|
||||
customStyleOptions: _customStyleOptions,
|
||||
);
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints.expand(),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Positioned(
|
||||
top: 30,
|
||||
child: Container(
|
||||
color: Color(0xFF00BFFF),
|
||||
child: AMapSwitchButton(
|
||||
label: Text(
|
||||
'自定义地图',
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
defaultValue: _customStyleOptions.enabled,
|
||||
onSwitchChanged: (value) => {
|
||||
if (_mapCreated)
|
||||
{
|
||||
setState(() {
|
||||
_customStyleOptions.enabled = value;
|
||||
})
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void onMapCreated(AMapController controller) {
|
||||
_mapCreated = true;
|
||||
}
|
||||
}
|
34
example/lib/pages/map/limit_map_bounds.dart
Normal file
34
example/lib/pages/map/limit_map_bounds.dart
Normal file
@ -0,0 +1,34 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class LimitMapBoundsPage extends BasePage {
|
||||
LimitMapBoundsPage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
_Body({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget amap = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
limitBounds: LatLngBounds(
|
||||
southwest: LatLng(39.83309, 116.290176),
|
||||
northeast: LatLng(39.99951, 116.501663)),
|
||||
);
|
||||
return Container(
|
||||
child: amap,
|
||||
);
|
||||
}
|
||||
}
|
426
example/lib/pages/map/map_all_config.dart
Normal file
426
example/lib/pages/map/map_all_config.dart
Normal file
@ -0,0 +1,426 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:amap_map_example/widgets/amap_switch_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
|
||||
class AllMapConfigDemoPage extends BasePage {
|
||||
AllMapConfigDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _MapUiBody();
|
||||
}
|
||||
}
|
||||
|
||||
class _MapUiBody extends StatefulWidget {
|
||||
@override
|
||||
State<StatefulWidget> createState() => _MapUiBodyState();
|
||||
}
|
||||
|
||||
class _MapUiBodyState extends State<_MapUiBody> {
|
||||
//默认显示在北京天安门
|
||||
static final CameraPosition _kInitialPosition = const CameraPosition(
|
||||
target: LatLng(39.909187, 116.397451),
|
||||
zoom: 10.0,
|
||||
);
|
||||
|
||||
///地图类型
|
||||
MapType _mapType = MapType.normal;
|
||||
|
||||
///显示路况开关
|
||||
bool _trafficEnabled = false;
|
||||
|
||||
/// 地图poi是否允许点击
|
||||
bool _touchPoiEnabled = false;
|
||||
|
||||
///是否显示3D建筑物
|
||||
bool _buildingsEnabled = true;
|
||||
|
||||
///是否显示底图文字标注
|
||||
bool _labelsEnabled = true;
|
||||
|
||||
///是否显示指南针
|
||||
bool _compassEnabled = false;
|
||||
|
||||
///是否显示比例尺
|
||||
bool _scaleEnabled = true;
|
||||
|
||||
///是否支持缩放手势
|
||||
bool _zoomGesturesEnabled = true;
|
||||
|
||||
///是否支持滑动手势
|
||||
bool _scrollGesturesEnabled = true;
|
||||
|
||||
///是否支持旋转手势
|
||||
bool _rotateGesturesEnabled = true;
|
||||
|
||||
///是否支持倾斜手势
|
||||
bool _tiltGesturesEnabled = true;
|
||||
|
||||
late AMapController _controller;
|
||||
|
||||
CustomStyleOptions _customStyleOptions = CustomStyleOptions(false);
|
||||
|
||||
///自定义定位小蓝点
|
||||
MyLocationStyleOptions _myLocationStyleOptions =
|
||||
MyLocationStyleOptions(false);
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadCustomData();
|
||||
}
|
||||
|
||||
void _loadCustomData() async {
|
||||
ByteData styleByteData = await rootBundle.load('assets/style.data');
|
||||
_customStyleOptions.styleData = styleByteData.buffer.asUint8List();
|
||||
ByteData styleExtraByteData =
|
||||
await rootBundle.load('assets/style_extra.data');
|
||||
_customStyleOptions.styleExtraData =
|
||||
styleExtraByteData.buffer.asUint8List();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget map = AMapWidget(
|
||||
///必须正确设置的合规隐私声明,否则SDK不会工作,会造成地图白屏等问题。
|
||||
privacyStatement: ConstConfig.amapPrivacyStatement,
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
initialCameraPosition: _kInitialPosition,
|
||||
mapType: _mapType,
|
||||
trafficEnabled: _trafficEnabled,
|
||||
buildingsEnabled: _buildingsEnabled,
|
||||
compassEnabled: _compassEnabled,
|
||||
labelsEnabled: _labelsEnabled,
|
||||
scaleEnabled: _scaleEnabled,
|
||||
touchPoiEnabled: _touchPoiEnabled,
|
||||
rotateGesturesEnabled: _rotateGesturesEnabled,
|
||||
scrollGesturesEnabled: _scrollGesturesEnabled,
|
||||
tiltGesturesEnabled: _tiltGesturesEnabled,
|
||||
zoomGesturesEnabled: _zoomGesturesEnabled,
|
||||
onMapCreated: onMapCreated,
|
||||
customStyleOptions: _customStyleOptions,
|
||||
myLocationStyleOptions: _myLocationStyleOptions,
|
||||
onLocationChanged: _onLocationChanged,
|
||||
onCameraMove: _onCameraMove,
|
||||
onCameraMoveEnd: _onCameraMoveEnd,
|
||||
onTap: _onMapTap,
|
||||
onLongPress: _onMapLongPress,
|
||||
onPoiTouched: _onMapPoiTouched,
|
||||
);
|
||||
|
||||
Widget _mapTypeRadio(String label, MapType radioValue) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(label),
|
||||
Radio(
|
||||
value: radioValue,
|
||||
groupValue: _mapType,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_mapType = value as MapType;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
final List<Widget> _mapTypeList = [
|
||||
_mapTypeRadio('普通地图', MapType.normal),
|
||||
_mapTypeRadio('卫星地图', MapType.satellite),
|
||||
_mapTypeRadio('导航地图', MapType.navi),
|
||||
_mapTypeRadio('公交地图', MapType.bus),
|
||||
_mapTypeRadio('黑夜模式', MapType.night),
|
||||
];
|
||||
|
||||
//ui控制
|
||||
final List<Widget> _uiOptions = [
|
||||
AMapSwitchButton(
|
||||
label: Text('显示路况'),
|
||||
defaultValue: _trafficEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_trafficEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示3D建筑物'),
|
||||
defaultValue: _buildingsEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_buildingsEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示指南针'),
|
||||
defaultValue: _compassEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_compassEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示地图文字'),
|
||||
defaultValue: _labelsEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_labelsEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示比例尺'),
|
||||
defaultValue: _scaleEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_scaleEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('点击Poi'),
|
||||
defaultValue: _touchPoiEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_touchPoiEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('自定义地图'),
|
||||
defaultValue: _customStyleOptions.enabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_customStyleOptions.enabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
//手势开关
|
||||
final List<Widget> gesturesOptions = [
|
||||
AMapSwitchButton(
|
||||
label: Text('旋转'),
|
||||
defaultValue: _rotateGesturesEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_rotateGesturesEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('滑动'),
|
||||
defaultValue: _scrollGesturesEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_scrollGesturesEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('倾斜'),
|
||||
defaultValue: _tiltGesturesEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_tiltGesturesEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('缩放'),
|
||||
defaultValue: _zoomGesturesEnabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_zoomGesturesEnabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
Widget _mapTypeOptions() {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('地图样式', style: TextStyle(fontWeight: FontWeight.w600)),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: createGridView(_mapTypeList),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _myLocationStyleContainer() {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
// Text('定位小蓝点', style: TextStyle(fontWeight: FontWeight.w600)),
|
||||
AMapSwitchButton(
|
||||
label:
|
||||
Text('定位小蓝点', style: TextStyle(fontWeight: FontWeight.w600)),
|
||||
defaultValue: _myLocationStyleOptions.enabled,
|
||||
onSwitchChanged: (value) => {
|
||||
setState(() {
|
||||
_myLocationStyleOptions.enabled = value;
|
||||
})
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _uiOptionsWidget() {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('UI操作', style: TextStyle(fontWeight: FontWeight.w600)),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: createGridView(_uiOptions),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _gesturesOptiosWeidget() {
|
||||
return Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text('手势控制', style: TextStyle(fontWeight: FontWeight.w600)),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: createGridView(gesturesOptions),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _optionsItem() {
|
||||
return Column(
|
||||
children: [
|
||||
_mapTypeOptions(),
|
||||
_myLocationStyleContainer(),
|
||||
_uiOptionsWidget(),
|
||||
_gesturesOptiosWeidget(),
|
||||
TextButton(
|
||||
child: const Text('moveCamera到首开'),
|
||||
onPressed: _moveCameraToShoukai,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height * 0.6,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Container(
|
||||
child: _optionsItem(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void onMapCreated(AMapController controller) {
|
||||
setState(() {
|
||||
_controller = controller;
|
||||
printApprovalNumber();
|
||||
});
|
||||
}
|
||||
|
||||
void printApprovalNumber() async {
|
||||
String mapContentApprovalNumber =
|
||||
(await _controller.getMapContentApprovalNumber())!;
|
||||
String satelliteImageApprovalNumber =
|
||||
(await _controller.getSatelliteImageApprovalNumber())!;
|
||||
print('地图审图号(普通地图): $mapContentApprovalNumber');
|
||||
print('地图审图号(卫星地图): $satelliteImageApprovalNumber');
|
||||
}
|
||||
|
||||
Widget createGridView(List<Widget> widgets) {
|
||||
return GridView.count(
|
||||
primary: false,
|
||||
physics: new NeverScrollableScrollPhysics(),
|
||||
//水平子Widget之间间距
|
||||
crossAxisSpacing: 1.0,
|
||||
//垂直子Widget之间间距
|
||||
mainAxisSpacing: 0.5,
|
||||
//一行的Widget数量
|
||||
crossAxisCount: 2,
|
||||
//宽高比
|
||||
childAspectRatio: 4,
|
||||
children: widgets,
|
||||
shrinkWrap: true);
|
||||
}
|
||||
|
||||
//移动地图中心点到首开广场
|
||||
void _moveCameraToShoukai() {
|
||||
_controller.moveCamera(CameraUpdate.newCameraPosition(CameraPosition(
|
||||
target: LatLng(39.993306, 116.473004),
|
||||
zoom: 18,
|
||||
tilt: 30,
|
||||
bearing: 30)));
|
||||
}
|
||||
|
||||
void _onLocationChanged(AMapLocation location) {
|
||||
print('_onLocationChanged ${location.toJson()}');
|
||||
}
|
||||
|
||||
void _onCameraMove(CameraPosition cameraPosition) {
|
||||
print('onCameraMove===> ${cameraPosition.toMap()}');
|
||||
}
|
||||
|
||||
void _onCameraMoveEnd(CameraPosition cameraPosition) {
|
||||
print('_onCameraMoveEnd===> ${cameraPosition.toMap()}');
|
||||
}
|
||||
|
||||
void _onMapTap(LatLng latLng) {
|
||||
print('_onMapTap===> ${latLng.toJson()}');
|
||||
}
|
||||
|
||||
void _onMapLongPress(LatLng latLng) {
|
||||
print('_onMapLongPress===> ${latLng.toJson()}');
|
||||
}
|
||||
|
||||
void _onMapPoiTouched(AMapPoi poi) {
|
||||
print('_onMapPoiTouched===> ${poi.toJson()}');
|
||||
}
|
||||
}
|
52
example/lib/pages/map/map_my_location.dart
Normal file
52
example/lib/pages/map/map_my_location.dart
Normal file
@ -0,0 +1,52 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
|
||||
class MyLocationPage extends BasePage {
|
||||
MyLocationPage(String title, String subTitle) : super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
_Body({Key? key}) : super(key: key);
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_requestLocaitonPermission();
|
||||
}
|
||||
|
||||
@override
|
||||
void reassemble() {
|
||||
super.reassemble();
|
||||
_requestLocaitonPermission();
|
||||
}
|
||||
|
||||
void _requestLocaitonPermission() async {
|
||||
PermissionStatus status = await Permission.location.request();
|
||||
print('permissionStatus=====> $status');
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget amap = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
myLocationStyleOptions: MyLocationStyleOptions(
|
||||
true,
|
||||
circleFillColor: Colors.lightBlue,
|
||||
circleStrokeColor: Colors.blue,
|
||||
circleStrokeWidth: 1,
|
||||
),
|
||||
);
|
||||
return Container(
|
||||
child: amap,
|
||||
);
|
||||
}
|
||||
}
|
141
example/lib/pages/map/min_max_zoom.dart
Normal file
141
example/lib/pages/map/min_max_zoom.dart
Normal file
@ -0,0 +1,141 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MinMaxZoomDemoPage extends BasePage {
|
||||
MinMaxZoomDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
_Body({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
final double _minZoom = 10;
|
||||
final double _maxZoom = 15;
|
||||
String? _currentZoom;
|
||||
late AMapController _mapController;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget amap = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
onMapCreated: _onMapCreated,
|
||||
onCameraMove: _onCameraMove,
|
||||
onCameraMoveEnd: _onCameraMoveEnd,
|
||||
minMaxZoomPreference: MinMaxZoomPreference(_minZoom, _maxZoom),
|
||||
);
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints.expand(),
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: amap,
|
||||
),
|
||||
Positioned(
|
||||
top: 5,
|
||||
left: 15,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
color: Colors.grey,
|
||||
padding: EdgeInsets.all(5),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
'当前限制的最小最大缩放级别是:[$_minZoom, $_maxZoom]',
|
||||
style: TextStyle(color: Colors.blue),
|
||||
),
|
||||
),
|
||||
_currentZoom != null
|
||||
? Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
color: Colors.grey,
|
||||
padding: EdgeInsets.all(5),
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
_currentZoom!,
|
||||
style: TextStyle(color: Colors.white),
|
||||
))
|
||||
: SizedBox(),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 5,
|
||||
bottom: 5,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
InkResponse(
|
||||
child: Container(
|
||||
child: Icon(
|
||||
Icons.add,
|
||||
color: Colors.white,
|
||||
),
|
||||
width: 40,
|
||||
height: 40,
|
||||
color: Colors.blue,
|
||||
),
|
||||
onTap: _zoomIn,
|
||||
),
|
||||
InkResponse(
|
||||
child: Container(
|
||||
child: Icon(
|
||||
Icons.remove,
|
||||
color: Colors.white,
|
||||
),
|
||||
color: Colors.blue,
|
||||
width: 40,
|
||||
height: 40,
|
||||
),
|
||||
onTap: _zoomOut,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onMapCreated(AMapController controller) {
|
||||
_mapController = controller;
|
||||
}
|
||||
|
||||
//移动视野
|
||||
void _onCameraMove(CameraPosition cameraPosition) {}
|
||||
|
||||
//移动地图结束
|
||||
void _onCameraMoveEnd(CameraPosition cameraPosition) {
|
||||
setState(() {
|
||||
_currentZoom = '当前缩放级别:${cameraPosition.zoom}';
|
||||
});
|
||||
}
|
||||
|
||||
//级别加1
|
||||
void _zoomIn() {
|
||||
_mapController.moveCamera(
|
||||
CameraUpdate.zoomIn(),
|
||||
animated: true,
|
||||
);
|
||||
}
|
||||
|
||||
//级别减1
|
||||
void _zoomOut() {
|
||||
_mapController.moveCamera(
|
||||
CameraUpdate.zoomOut(),
|
||||
animated: true,
|
||||
);
|
||||
}
|
||||
}
|
42
example/lib/pages/map/multi_map.dart
Normal file
42
example/lib/pages/map/multi_map.dart
Normal file
@ -0,0 +1,42 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MultiMapDemoPage extends BasePage {
|
||||
MultiMapDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return const _MultiMapDemoBody();
|
||||
}
|
||||
}
|
||||
|
||||
class _MultiMapDemoBody extends StatefulWidget {
|
||||
const _MultiMapDemoBody();
|
||||
@override
|
||||
State<StatefulWidget> createState() => _MultiMapDemoState();
|
||||
}
|
||||
|
||||
class _MultiMapDemoState extends State<_MultiMapDemoBody> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
Expanded(child: AMapWidget()),
|
||||
Padding(padding: EdgeInsets.all(5.0)),
|
||||
//第二个地图指定初始位置为上海
|
||||
Expanded(
|
||||
child: AMapWidget(
|
||||
initialCameraPosition:
|
||||
CameraPosition(target: LatLng(31.230378, 121.473658)),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
76
example/lib/pages/map/show_map_page.dart
Normal file
76
example/lib/pages/map/show_map_page.dart
Normal file
@ -0,0 +1,76 @@
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
|
||||
class ShowMapPage extends BasePage {
|
||||
ShowMapPage(String title, String subTitle) : super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _ShowMapPageBody();
|
||||
}
|
||||
}
|
||||
|
||||
class _ShowMapPageBody extends StatefulWidget {
|
||||
@override
|
||||
State<StatefulWidget> createState() => _ShowMapPageState();
|
||||
}
|
||||
|
||||
class _ShowMapPageState extends State<_ShowMapPageBody> {
|
||||
List<Widget> _approvalNumberWidget = <Widget>[];
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget map = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
onMapCreated: onMapCreated,
|
||||
);
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints.expand(),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Positioned(
|
||||
right: 10,
|
||||
bottom: 15,
|
||||
child: Container(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: _approvalNumberWidget),
|
||||
))
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
late AMapController _mapController;
|
||||
void onMapCreated(AMapController controller) {
|
||||
setState(() {
|
||||
_mapController = controller;
|
||||
getApprovalNumber();
|
||||
});
|
||||
}
|
||||
|
||||
/// 获取审图号
|
||||
void getApprovalNumber() async {
|
||||
//普通地图审图号
|
||||
String mapContentApprovalNumber =
|
||||
(await _mapController.getMapContentApprovalNumber())!;
|
||||
//卫星地图审图号
|
||||
String satelliteImageApprovalNumber =
|
||||
(await _mapController.getSatelliteImageApprovalNumber())!;
|
||||
setState(() {
|
||||
_approvalNumberWidget.add(Text(mapContentApprovalNumber));
|
||||
_approvalNumberWidget.add(Text(satelliteImageApprovalNumber));
|
||||
});
|
||||
print('地图审图号(普通地图): $mapContentApprovalNumber');
|
||||
print('地图审图号(卫星地图): $satelliteImageApprovalNumber');
|
||||
}
|
||||
}
|
91
example/lib/pages/overlays/marker_add_after_map.dart
Normal file
91
example/lib/pages/overlays/marker_add_after_map.dart
Normal file
@ -0,0 +1,91 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MarkerAddAfterMapPage extends BasePage {
|
||||
MarkerAddAfterMapPage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
static final LatLng defaultPosition = const LatLng(39.909187, 116.397451);
|
||||
//需要先设置一个空的map赋值给AMapWidget的markers,否则后续无法添加marker
|
||||
final Map<String, Marker> _markers = <String, Marker>{};
|
||||
LatLng _currentLatLng = defaultPosition;
|
||||
//添加一个marker
|
||||
void _addMarker() {
|
||||
final _markerPosition =
|
||||
LatLng(_currentLatLng.latitude, _currentLatLng.longitude + 2 / 1000);
|
||||
final Marker marker = Marker(
|
||||
position: _markerPosition,
|
||||
//使用默认hue的方式设置Marker的图标
|
||||
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueOrange),
|
||||
);
|
||||
//调用setState触发AMapWidget的更新,从而完成marker的添加
|
||||
setState(() {
|
||||
_currentLatLng = _markerPosition;
|
||||
//将新的marker添加到map里
|
||||
_markers[marker.id] = marker;
|
||||
});
|
||||
}
|
||||
|
||||
TextButton _createMyFloatButton(String label, VoidCallback onPressed) {
|
||||
return TextButton(
|
||||
onPressed: onPressed,
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStateProperty.all(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
|
||||
//文字颜色
|
||||
foregroundColor: MaterialStateProperty.all(Colors.white),
|
||||
//水波纹颜色
|
||||
overlayColor: MaterialStateProperty.all(Colors.blueAccent),
|
||||
//背景颜色
|
||||
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||
//设置按下时的背景颜色
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return Colors.blueAccent;
|
||||
}
|
||||
//默认背景颜色
|
||||
return Colors.blue;
|
||||
}),
|
||||
),
|
||||
child: Text(label),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget amap = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
// //创建地图时,给marker属性赋值一个空的set,否则后续无法添加marker
|
||||
markers: Set<Marker>.of(_markers.values),
|
||||
);
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 10,
|
||||
child: amap,
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: _createMyFloatButton('添加marker', _addMarker),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
42
example/lib/pages/overlays/marker_add_with_map.dart
Normal file
42
example/lib/pages/overlays/marker_add_with_map.dart
Normal file
@ -0,0 +1,42 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MarkerAddWithMapPage extends BasePage {
|
||||
MarkerAddWithMapPage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
static final LatLng mapCenter = const LatLng(39.909187, 116.397451);
|
||||
final Map<String, Marker> _initMarkerMap = <String, Marker>{};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
LatLng position = LatLng(mapCenter.latitude + sin(i * pi / 12.0) / 20.0,
|
||||
mapCenter.longitude + cos(i * pi / 12.0) / 20.0);
|
||||
Marker marker = Marker(position: position);
|
||||
_initMarkerMap[marker.id] = marker;
|
||||
}
|
||||
|
||||
final AMapWidget amap = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
markers: Set<Marker>.of(_initMarkerMap.values),
|
||||
);
|
||||
return Container(
|
||||
child: amap,
|
||||
);
|
||||
}
|
||||
}
|
343
example/lib/pages/overlays/marker_config.dart
Normal file
343
example/lib/pages/overlays/marker_config.dart
Normal file
@ -0,0 +1,343 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:amap_map_example/widgets/amap_switch_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'dart:math';
|
||||
|
||||
class MarkerConfigDemoPage extends BasePage {
|
||||
MarkerConfigDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _Body();
|
||||
}
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
const _Body();
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<_Body> {
|
||||
static final LatLng mapCenter = const LatLng(39.909187, 116.397451);
|
||||
|
||||
Map<String, Marker> _markers = <String, Marker>{};
|
||||
BitmapDescriptor? _markerIcon;
|
||||
String? selectedMarkerId;
|
||||
|
||||
void _onMapCreated(AMapController controller) {}
|
||||
|
||||
///通过BitmapDescriptor.fromAssetImage的方式获取图片
|
||||
Future<void> _createMarkerImageFromAsset(BuildContext context) async {
|
||||
if (_markerIcon == null) {
|
||||
final ImageConfiguration imageConfiguration =
|
||||
createLocalImageConfiguration(context);
|
||||
BitmapDescriptor.fromAssetImage(imageConfiguration, 'assets/start.png')
|
||||
.then(_updateBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
///通过BitmapDescriptor.fromBytes的方式获取图片
|
||||
Future<void> _createMarkerImageFromBytes(BuildContext context) async {
|
||||
final Completer<BitmapDescriptor> bitmapIcon =
|
||||
Completer<BitmapDescriptor>();
|
||||
final ImageConfiguration config = createLocalImageConfiguration(context);
|
||||
|
||||
const AssetImage('assets/end.png')
|
||||
.resolve(config)
|
||||
.addListener(ImageStreamListener((ImageInfo image, bool sync) async {
|
||||
final ByteData bytes =
|
||||
(await image.image.toByteData(format: ImageByteFormat.png))!;
|
||||
final BitmapDescriptor bitmap =
|
||||
BitmapDescriptor.fromBytes(bytes.buffer.asUint8List());
|
||||
bitmapIcon.complete(bitmap);
|
||||
}));
|
||||
|
||||
bitmapIcon.future.then((value) => _updateBitmap(value));
|
||||
}
|
||||
|
||||
void _updateBitmap(BitmapDescriptor bitmap) {
|
||||
setState(() {
|
||||
_markerIcon = bitmap;
|
||||
});
|
||||
}
|
||||
|
||||
void _add() {
|
||||
final int markerCount = _markers.length;
|
||||
LatLng markPostion = LatLng(
|
||||
mapCenter.latitude + sin(markerCount * pi / 12.0) / 20.0,
|
||||
mapCenter.longitude + cos(markerCount * pi / 12.0) / 20.0);
|
||||
final Marker marker = Marker(
|
||||
position: markPostion,
|
||||
icon: _markerIcon!,
|
||||
infoWindow: InfoWindow(title: '第 $markerCount 个Marker'),
|
||||
onTap: (markerId) => _onMarkerTapped(markerId),
|
||||
onDragEnd: (markerId, endPosition) =>
|
||||
_onMarkerDragEnd(markerId, endPosition),
|
||||
);
|
||||
|
||||
setState(() {
|
||||
_markers[marker.id] = marker;
|
||||
});
|
||||
}
|
||||
|
||||
void _onMarkerTapped(String markerId) {
|
||||
final Marker? tappedMarker = _markers[markerId];
|
||||
final String? title = tappedMarker!.infoWindow.title;
|
||||
print('$title 被点击了,markerId: $markerId');
|
||||
setState(() {
|
||||
selectedMarkerId = markerId;
|
||||
});
|
||||
}
|
||||
|
||||
void _onMarkerDragEnd(String markerId, LatLng position) {
|
||||
final Marker? tappedMarker = _markers[markerId];
|
||||
final String? title = tappedMarker!.infoWindow.title;
|
||||
print('$title markerId: $markerId 被拖拽到了: $position');
|
||||
}
|
||||
|
||||
void _remove() {
|
||||
final Marker? selectedMarker = _markers[selectedMarkerId];
|
||||
//有选中的Marker
|
||||
if (selectedMarker != null) {
|
||||
setState(() {
|
||||
_markers.remove(selectedMarkerId);
|
||||
});
|
||||
} else {
|
||||
print('无选中的Marker,无法删除');
|
||||
}
|
||||
}
|
||||
|
||||
void _removeAll() {
|
||||
if (_markers.length > 0) {
|
||||
setState(() {
|
||||
_markers.clear();
|
||||
selectedMarkerId = null.toString();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _changeInfo() async {
|
||||
final Marker marker = _markers[selectedMarkerId]!;
|
||||
final String newTitle = marker.infoWindow.title! + '*';
|
||||
if (selectedMarkerId != null) {
|
||||
setState(() {
|
||||
_markers[selectedMarkerId!] = marker.copyWith(
|
||||
infoWindowParam: marker.infoWindow.copyWith(
|
||||
titleParam: newTitle,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _changeAnchor() {
|
||||
final Marker marker = _markers[selectedMarkerId]!;
|
||||
final Offset currentAnchor = marker.anchor;
|
||||
double dx = 0;
|
||||
double dy = 0;
|
||||
if (currentAnchor.dx < 1) {
|
||||
dx = currentAnchor.dx + 0.1;
|
||||
} else {
|
||||
dx = 0;
|
||||
}
|
||||
if (currentAnchor.dy < 1) {
|
||||
dy = currentAnchor.dy + 0.1;
|
||||
} else {
|
||||
dy = 0;
|
||||
}
|
||||
final Offset newAnchor = Offset(dx, dy);
|
||||
setState(() {
|
||||
_markers[selectedMarkerId!] = marker.copyWith(
|
||||
anchorParam: newAnchor,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void _changePosition() {
|
||||
final Marker marker = _markers[selectedMarkerId]!;
|
||||
final LatLng current = marker.position;
|
||||
final Offset offset = Offset(
|
||||
mapCenter.latitude - current.latitude,
|
||||
mapCenter.longitude - current.longitude,
|
||||
);
|
||||
setState(() {
|
||||
_markers[selectedMarkerId!] = marker.copyWith(
|
||||
positionParam: LatLng(
|
||||
mapCenter.latitude + offset.dy,
|
||||
mapCenter.longitude + offset.dx,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _changeAlpha() async {
|
||||
final Marker marker = _markers[selectedMarkerId]!;
|
||||
final double current = marker.alpha;
|
||||
setState(() {
|
||||
_markers[selectedMarkerId!] = marker.copyWith(
|
||||
alphaParam: current < 0.1 ? 1.0 : current * 0.75,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _changeRotation() async {
|
||||
final Marker marker = _markers[selectedMarkerId]!;
|
||||
final double current = marker.rotation;
|
||||
setState(() {
|
||||
_markers[selectedMarkerId!] = marker.copyWith(
|
||||
rotationParam: current == 330.0 ? 0.0 : current + 30.0,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _toggleVisible(value) async {
|
||||
final Marker marker = _markers[selectedMarkerId]!;
|
||||
setState(() {
|
||||
_markers[selectedMarkerId!] = marker.copyWith(
|
||||
visibleParam: value,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _toggleDraggable(value) async {
|
||||
final Marker marker = _markers[selectedMarkerId]!;
|
||||
setState(() {
|
||||
_markers[selectedMarkerId!] = marker.copyWith(
|
||||
draggableParam: value,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
///以下几种获取自定图片的方式使用其中一种即可。
|
||||
//最简单的方式
|
||||
if (null == _markerIcon) {
|
||||
_markerIcon = BitmapDescriptor.fromIconPath('assets/location_marker.png');
|
||||
}
|
||||
|
||||
//通过BitmapDescriptor.fromAssetImage的方式获取图片
|
||||
// _createMarkerImageFromAsset(context);
|
||||
//通过BitmapDescriptor.fromBytes的方式获取图片
|
||||
// _createMarkerImageFromBytes(context);
|
||||
|
||||
final AMapWidget map = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
onMapCreated: _onMapCreated,
|
||||
markers: Set<Marker>.of(_markers.values),
|
||||
);
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height * 0.6,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('添加'),
|
||||
onPressed: _add,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('移除'),
|
||||
onPressed:
|
||||
(selectedMarkerId == null) ? null : _remove,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('更新InfoWidow'),
|
||||
onPressed:
|
||||
(selectedMarkerId == null) ? null : _changeInfo,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改锚点'),
|
||||
onPressed: (selectedMarkerId == null)
|
||||
? null
|
||||
: _changeAnchor,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改透明度'),
|
||||
onPressed: (selectedMarkerId == null)
|
||||
? null
|
||||
: _changeAlpha,
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('全部移除'),
|
||||
onPressed: _markers.length > 0 ? _removeAll : null,
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('允许拖动'),
|
||||
onSwitchChanged: (selectedMarkerId == null)
|
||||
? null
|
||||
: _toggleDraggable,
|
||||
defaultValue: false,
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示'),
|
||||
onSwitchChanged: (selectedMarkerId == null)
|
||||
? null
|
||||
: _toggleVisible,
|
||||
defaultValue: true,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改坐标'),
|
||||
onPressed: (selectedMarkerId == null)
|
||||
? null
|
||||
: _changePosition,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改旋转角度'),
|
||||
onPressed: (selectedMarkerId == null)
|
||||
? null
|
||||
: _changeRotation,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
99
example/lib/pages/overlays/marker_custom_icon.dart
Normal file
99
example/lib/pages/overlays/marker_custom_icon.dart
Normal file
@ -0,0 +1,99 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/const_config.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MarkerCustomIconPage extends BasePage {
|
||||
MarkerCustomIconPage(String title, String subTitle) : super(title, subTitle);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => _Body();
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
@override
|
||||
_BodyState createState() => _BodyState();
|
||||
}
|
||||
|
||||
class _BodyState extends State<_Body> {
|
||||
static final LatLng markerPosition = const LatLng(39.909187, 116.397451);
|
||||
final Map<String, Marker> _initMarkerMap = <String, Marker>{};
|
||||
String? _currentMarkerId;
|
||||
bool _hasInitMarker = false;
|
||||
static final String _startIconPath = 'assets/start.png';
|
||||
static final String _endIconPath = 'assets/end.png';
|
||||
String _iconPath = _startIconPath;
|
||||
void _initMarker(BuildContext context) async {
|
||||
if (_hasInitMarker) {
|
||||
return;
|
||||
}
|
||||
Marker marker = Marker(
|
||||
position: markerPosition,
|
||||
icon: BitmapDescriptor.fromIconPath(_iconPath));
|
||||
setState(() {
|
||||
_hasInitMarker = true;
|
||||
_currentMarkerId = marker.id;
|
||||
_initMarkerMap[marker.id] = marker;
|
||||
});
|
||||
}
|
||||
|
||||
void _updateMarkerIcon() async {
|
||||
Marker marker = _initMarkerMap[_currentMarkerId]!;
|
||||
setState(() {
|
||||
_iconPath = _iconPath == _startIconPath ? _endIconPath : _startIconPath;
|
||||
_initMarkerMap[_currentMarkerId!] =
|
||||
marker.copyWith(iconParam: BitmapDescriptor.fromIconPath(_iconPath));
|
||||
});
|
||||
}
|
||||
|
||||
TextButton _createMyFloatButton(String label, VoidCallback onPressed) {
|
||||
return TextButton(
|
||||
onPressed: onPressed,
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStateProperty.all(
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
|
||||
//文字颜色
|
||||
foregroundColor: MaterialStateProperty.all(Colors.white),
|
||||
//水波纹颜色
|
||||
overlayColor: MaterialStateProperty.all(Colors.blueAccent),
|
||||
//背景颜色
|
||||
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||
//设置按下时的背景颜色
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return Colors.blueAccent;
|
||||
}
|
||||
//默认背景颜色
|
||||
return Colors.blue;
|
||||
}),
|
||||
),
|
||||
child: Text(label),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_initMarker(context);
|
||||
final AMapWidget amap = AMapWidget(
|
||||
apiKey: ConstConfig.amapApiKeys,
|
||||
markers: Set<Marker>.of(_initMarkerMap.values),
|
||||
);
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 10,
|
||||
child: amap,
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: _createMyFloatButton('更改图标', _updateMarkerIcon),
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
221
example/lib/pages/overlays/place_polygon.dart
Normal file
221
example/lib/pages/overlays/place_polygon.dart
Normal file
@ -0,0 +1,221 @@
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/widgets/amap_switch_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
|
||||
class PolygonDemoPage extends BasePage {
|
||||
PolygonDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _Body();
|
||||
}
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
const _Body();
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<_Body> {
|
||||
_State();
|
||||
|
||||
// Values when toggling Polygon color
|
||||
int colorsIndex = 0;
|
||||
List<Color> colors = <Color>[
|
||||
Colors.purple,
|
||||
Colors.red,
|
||||
Colors.green,
|
||||
Colors.pink,
|
||||
];
|
||||
|
||||
Map<String, Polygon> _polygons = <String, Polygon>{};
|
||||
String? selectedPolygonId;
|
||||
|
||||
void _onMapCreated(AMapController controller) {}
|
||||
|
||||
LatLng _createLatLng(double lat, double lng) {
|
||||
return LatLng(lat, lng);
|
||||
}
|
||||
|
||||
List<LatLng> _createPoints() {
|
||||
final List<LatLng> points = <LatLng>[];
|
||||
final int polygonCount = _polygons.length;
|
||||
final double offset = polygonCount * 0.01;
|
||||
points.add(_createLatLng(39.835334 + offset, 116.3710069));
|
||||
points.add(_createLatLng(39.843082 + offset, 116.3709830));
|
||||
points.add(_createLatLng(39.845932 + offset, 116.3642213));
|
||||
points.add(_createLatLng(39.845924 + offset, 116.3595219));
|
||||
points.add(_createLatLng(39.841562 + offset, 116.345568));
|
||||
points.add(_createLatLng(39.835347 + offset, 116.34575));
|
||||
return points;
|
||||
}
|
||||
|
||||
void _add() {
|
||||
final Polygon polygon = Polygon(
|
||||
strokeColor: colors[++colorsIndex % colors.length],
|
||||
fillColor: colors[++colorsIndex % colors.length],
|
||||
strokeWidth: 15,
|
||||
points: _createPoints(),
|
||||
);
|
||||
setState(() {
|
||||
selectedPolygonId = polygon.id;
|
||||
_polygons[polygon.id] = polygon;
|
||||
});
|
||||
}
|
||||
|
||||
void _remove() {
|
||||
if (selectedPolygonId != null) {
|
||||
//有选中的Marker
|
||||
setState(() {
|
||||
_polygons.remove(selectedPolygonId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _changeStrokeWidth() {
|
||||
final Polygon? selectedPolygon = _polygons[selectedPolygonId];
|
||||
if (selectedPolygon != null) {
|
||||
double currentWidth = selectedPolygon.strokeWidth;
|
||||
if (currentWidth < 50) {
|
||||
currentWidth += 10;
|
||||
} else {
|
||||
currentWidth = 5;
|
||||
}
|
||||
//有选中的Polygon
|
||||
setState(() {
|
||||
_polygons[selectedPolygonId!] =
|
||||
selectedPolygon.copyWith(strokeWidthParam: currentWidth);
|
||||
});
|
||||
} else {
|
||||
print('无选中的Polygon,无法修改宽度');
|
||||
}
|
||||
}
|
||||
|
||||
void _changeColors() {
|
||||
final Polygon polygon = _polygons[selectedPolygonId]!;
|
||||
setState(() {
|
||||
_polygons[selectedPolygonId!] = polygon.copyWith(
|
||||
strokeColorParam: colors[++colorsIndex % colors.length],
|
||||
fillColorParam: colors[(colorsIndex + 1) % colors.length],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _toggleVisible(value) async {
|
||||
final Polygon polygon = _polygons[selectedPolygonId]!;
|
||||
setState(() {
|
||||
_polygons[selectedPolygonId!] = polygon.copyWith(
|
||||
visibleParam: value,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void _changePoints() {
|
||||
final Polygon polygon = _polygons[selectedPolygonId]!;
|
||||
List<LatLng> currentPoints = polygon.points;
|
||||
List<LatLng> newPoints = <LatLng>[];
|
||||
newPoints.addAll(currentPoints);
|
||||
newPoints.add(LatLng(39.828809, 116.360364));
|
||||
|
||||
setState(() {
|
||||
_polygons[selectedPolygonId!] = polygon.copyWith(
|
||||
pointsParam: newPoints,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget map = AMapWidget(
|
||||
initialCameraPosition:
|
||||
CameraPosition(target: LatLng(39.828809, 116.360364), zoom: 13),
|
||||
onMapCreated: _onMapCreated,
|
||||
polygons: Set<Polygon>.of(_polygons.values),
|
||||
);
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height * 0.6,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('添加'),
|
||||
onPressed: _add,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('删除'),
|
||||
onPressed:
|
||||
(selectedPolygonId == null) ? null : _remove,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改边框宽度'),
|
||||
onPressed: (selectedPolygonId == null)
|
||||
? null
|
||||
: _changeStrokeWidth,
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('修改边框和填充色'),
|
||||
onPressed: (selectedPolygonId == null)
|
||||
? null
|
||||
: _changeColors,
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示'),
|
||||
onSwitchChanged: (selectedPolygonId == null)
|
||||
? null
|
||||
: _toggleVisible,
|
||||
defaultValue: true,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改坐标'),
|
||||
onPressed: (selectedPolygonId == null)
|
||||
? null
|
||||
: _changePoints,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
304
example/lib/pages/overlays/place_polyline.dart
Normal file
304
example/lib/pages/overlays/place_polyline.dart
Normal file
@ -0,0 +1,304 @@
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:amap_map_example/widgets/amap_switch_button.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
|
||||
class PolylineDemoPage extends BasePage {
|
||||
PolylineDemoPage(String title, String subTitle) : super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _Body();
|
||||
}
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
const _Body();
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<_Body> {
|
||||
_State();
|
||||
|
||||
// Values when toggling polyline color
|
||||
int colorsIndex = 0;
|
||||
List<Color> colors = <Color>[
|
||||
Colors.purple,
|
||||
Colors.red,
|
||||
Colors.green,
|
||||
Colors.pink,
|
||||
];
|
||||
Map<String, Polyline> _polylines = <String, Polyline>{};
|
||||
String? selectedPolylineId;
|
||||
|
||||
void _onMapCreated(AMapController controller) {}
|
||||
|
||||
List<LatLng> _createPoints() {
|
||||
final List<LatLng> points = <LatLng>[];
|
||||
final int polylineCount = _polylines.length;
|
||||
final double offset = polylineCount * -(0.01);
|
||||
points.add(LatLng(39.938698 + offset, 116.275177));
|
||||
points.add(LatLng(39.966069 + offset, 116.289253));
|
||||
points.add(LatLng(39.944226 + offset, 116.306076));
|
||||
points.add(LatLng(39.966069 + offset, 116.322899));
|
||||
points.add(LatLng(39.938698 + offset, 116.336975));
|
||||
return points;
|
||||
}
|
||||
|
||||
void _add() {
|
||||
final Polyline polyline = Polyline(
|
||||
color: colors[++colorsIndex % colors.length],
|
||||
width: 10,
|
||||
points: _createPoints(),
|
||||
onTap: _onPolylineTapped);
|
||||
setState(() {
|
||||
_polylines[polyline.id] = polyline;
|
||||
});
|
||||
}
|
||||
|
||||
void _remove() {
|
||||
final Polyline? selectedPolyline = _polylines[selectedPolylineId];
|
||||
//有选中的Marker
|
||||
if (selectedPolyline != null) {
|
||||
setState(() {
|
||||
_polylines.remove(selectedPolylineId);
|
||||
});
|
||||
} else {
|
||||
print('无选中的Polyline,无法删除');
|
||||
}
|
||||
}
|
||||
|
||||
void _changeWidth() {
|
||||
final Polyline? selectedPolyline = _polylines[selectedPolylineId]!;
|
||||
//有选中的Polyline
|
||||
if (selectedPolyline != null) {
|
||||
double currentWidth = selectedPolyline.width;
|
||||
if (currentWidth < 50) {
|
||||
currentWidth += 10;
|
||||
} else {
|
||||
currentWidth = 5;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_polylines[selectedPolylineId!] =
|
||||
selectedPolyline.copyWith(widthParam: currentWidth);
|
||||
});
|
||||
} else {
|
||||
print('无选中的Polyline,无法修改宽度');
|
||||
}
|
||||
}
|
||||
|
||||
void _onPolylineTapped(String polylineId) {
|
||||
print('Polyline: $polylineId 被点击了');
|
||||
setState(() {
|
||||
selectedPolylineId = polylineId;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _changeDashLineType() async {
|
||||
final Polyline? polyline = _polylines[selectedPolylineId];
|
||||
if (polyline == null) {
|
||||
return;
|
||||
}
|
||||
DashLineType currentType = polyline.dashLineType;
|
||||
if (currentType.index < DashLineType.circle.index) {
|
||||
currentType = DashLineType.values[currentType.index + 1];
|
||||
} else {
|
||||
currentType = DashLineType.none;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_polylines[selectedPolylineId!] =
|
||||
polyline.copyWith(dashLineTypeParam: currentType);
|
||||
});
|
||||
}
|
||||
|
||||
void _changeCapType() {
|
||||
final Polyline? polyline = _polylines[selectedPolylineId]!;
|
||||
if (polyline == null) {
|
||||
return;
|
||||
}
|
||||
CapType capType = polyline.capType;
|
||||
if (capType.index < CapType.round.index) {
|
||||
capType = CapType.values[capType.index + 1];
|
||||
} else {
|
||||
capType = CapType.butt;
|
||||
}
|
||||
setState(() {
|
||||
_polylines[selectedPolylineId!] =
|
||||
polyline.copyWith(capTypeParam: capType);
|
||||
});
|
||||
}
|
||||
|
||||
void _changeJointType() {
|
||||
final Polyline polyline = _polylines[selectedPolylineId]!;
|
||||
JoinType joinType = polyline.joinType;
|
||||
if (joinType.index < JoinType.round.index) {
|
||||
joinType = JoinType.values[joinType.index + 1];
|
||||
} else {
|
||||
joinType = JoinType.bevel;
|
||||
}
|
||||
setState(() {
|
||||
_polylines[selectedPolylineId!] =
|
||||
polyline.copyWith(joinTypeParam: joinType);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _changeAlpha() async {
|
||||
final Polyline polyline = _polylines[selectedPolylineId]!;
|
||||
final double current = polyline.alpha;
|
||||
setState(() {
|
||||
_polylines[selectedPolylineId!] = polyline.copyWith(
|
||||
alphaParam: current < 0.1 ? 1.0 : current * 0.75,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _toggleVisible(value) async {
|
||||
final Polyline polyline = _polylines[selectedPolylineId]!;
|
||||
setState(() {
|
||||
_polylines[selectedPolylineId!] = polyline.copyWith(
|
||||
visibleParam: value,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void _changeColor() {
|
||||
final Polyline polyline = _polylines[selectedPolylineId]!;
|
||||
setState(() {
|
||||
_polylines[selectedPolylineId!] = polyline.copyWith(
|
||||
colorParam: colors[++colorsIndex % colors.length],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void _changePoints() {
|
||||
final Polyline polyline = _polylines[selectedPolylineId]!;
|
||||
List<LatLng> currentPoints = polyline.points;
|
||||
List<LatLng> newPoints = <LatLng>[];
|
||||
newPoints.addAll(currentPoints);
|
||||
newPoints.add(LatLng(39.835347, 116.34575));
|
||||
|
||||
setState(() {
|
||||
_polylines[selectedPolylineId!] = polyline.copyWith(
|
||||
pointsParam: newPoints,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget map = AMapWidget(
|
||||
onMapCreated: _onMapCreated,
|
||||
polylines: Set<Polyline>.of(_polylines.values),
|
||||
);
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Container(
|
||||
height: MediaQuery.of(context).size.height * 0.6,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: map,
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Column(
|
||||
children: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('添加'),
|
||||
onPressed: _add,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('删除'),
|
||||
onPressed:
|
||||
(selectedPolylineId == null) ? null : _remove,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改线宽'),
|
||||
onPressed: (selectedPolylineId == null)
|
||||
? null
|
||||
: _changeWidth,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改透明度'),
|
||||
onPressed: (selectedPolylineId == null)
|
||||
? null
|
||||
: _changeAlpha,
|
||||
),
|
||||
AMapSwitchButton(
|
||||
label: Text('显示'),
|
||||
onSwitchChanged: (selectedPolylineId == null)
|
||||
? null
|
||||
: _toggleVisible,
|
||||
defaultValue: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
children: <Widget>[
|
||||
TextButton(
|
||||
child: const Text('修改颜色'),
|
||||
onPressed: (selectedPolylineId == null)
|
||||
? null
|
||||
: _changeColor,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改线头样式'),
|
||||
onPressed: (selectedPolylineId == null)
|
||||
? null
|
||||
: _changeCapType,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改连接样式'),
|
||||
onPressed: (selectedPolylineId == null)
|
||||
? null
|
||||
: _changeJointType,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改虚线类型'),
|
||||
onPressed: (selectedPolylineId == null)
|
||||
? null
|
||||
: _changeDashLineType,
|
||||
),
|
||||
TextButton(
|
||||
child: const Text('修改坐标'),
|
||||
onPressed: (selectedPolylineId == null)
|
||||
? null
|
||||
: _changePoints,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
124
example/lib/pages/overlays/polyline_geodesic.dart
Normal file
124
example/lib/pages/overlays/polyline_geodesic.dart
Normal file
@ -0,0 +1,124 @@
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
|
||||
class PolylineGeodesicDemoPage extends BasePage {
|
||||
PolylineGeodesicDemoPage(String title, String subTitle)
|
||||
: super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _Body();
|
||||
}
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
const _Body();
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<_Body> {
|
||||
_State();
|
||||
|
||||
// Values when toggling polyline color
|
||||
int colorsIndex = 0;
|
||||
List<Color> colors = <Color>[
|
||||
Colors.purple,
|
||||
Colors.red,
|
||||
Colors.green,
|
||||
Colors.pink,
|
||||
];
|
||||
Map<String, Polyline> _polylines = <String, Polyline>{};
|
||||
late String selectedPolylineId;
|
||||
AMapController? _controller;
|
||||
|
||||
void _onMapCreated(AMapController controller) {
|
||||
_controller = controller;
|
||||
}
|
||||
|
||||
List<LatLng> _createPoints() {
|
||||
final List<LatLng> points = <LatLng>[];
|
||||
final int polylineCount = _polylines.length;
|
||||
final int offset = polylineCount * (-1);
|
||||
points.add(LatLng(39.905151 + offset, 116.401726));
|
||||
points.add(LatLng(38.905151 + offset, 70.401726));
|
||||
return points;
|
||||
}
|
||||
|
||||
void _add() {
|
||||
final Polyline polyline = Polyline(
|
||||
color: colors[++colorsIndex % colors.length],
|
||||
width: 10,
|
||||
geodesic: true,
|
||||
points: _createPoints());
|
||||
|
||||
setState(() {
|
||||
_polylines[polyline.id] = polyline;
|
||||
});
|
||||
//移动到合适的范围
|
||||
LatLngBounds bound =
|
||||
LatLngBounds(southwest: LatLng(25.0, 70.0), northeast: LatLng(45, 117));
|
||||
CameraUpdate update = CameraUpdate.newLatLngBounds(bound, 10);
|
||||
_controller?.moveCamera(update);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget map = AMapWidget(
|
||||
onMapCreated: _onMapCreated,
|
||||
polylines: Set<Polyline>.of(_polylines.values),
|
||||
);
|
||||
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 10,
|
||||
child: map,
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: TextButton(
|
||||
onPressed: _add,
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStateProperty.all(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10))),
|
||||
//文字颜色
|
||||
foregroundColor: MaterialStateProperty.all(Colors.white),
|
||||
//水波纹颜色
|
||||
overlayColor: MaterialStateProperty.all(Colors.blueAccent),
|
||||
//背景颜色
|
||||
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||
//设置按下时的背景颜色
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return Colors.blueAccent;
|
||||
}
|
||||
//默认背景颜色
|
||||
return Colors.blue;
|
||||
}),
|
||||
),
|
||||
child: Text('添加大地曲线'),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
112
example/lib/pages/overlays/polyline_texture.dart
Normal file
112
example/lib/pages/overlays/polyline_texture.dart
Normal file
@ -0,0 +1,112 @@
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:amap_map/amap_map.dart';
|
||||
|
||||
class PolylineTextureDemoPage extends BasePage {
|
||||
PolylineTextureDemoPage(String title, String subTitle)
|
||||
: super(title, subTitle);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return _Body();
|
||||
}
|
||||
}
|
||||
|
||||
class _Body extends StatefulWidget {
|
||||
const _Body();
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<_Body> {
|
||||
_State();
|
||||
|
||||
Map<String, Polyline> _polylines = <String, Polyline>{};
|
||||
late String selectedPolylineId;
|
||||
|
||||
void _onMapCreated(AMapController controller) {}
|
||||
|
||||
List<LatLng> _createPoints() {
|
||||
final List<LatLng> points = <LatLng>[];
|
||||
final int polylineCount = _polylines.length;
|
||||
final double offset = polylineCount * -(0.01);
|
||||
points.add(LatLng(39.938698 + offset, 116.275177));
|
||||
points.add(LatLng(39.966069 + offset, 116.289253));
|
||||
points.add(LatLng(39.944226 + offset, 116.306076));
|
||||
points.add(LatLng(39.966069 + offset, 116.322899));
|
||||
points.add(LatLng(39.938698 + offset, 116.336975));
|
||||
return points;
|
||||
}
|
||||
|
||||
void _add() {
|
||||
final Polyline polyline = Polyline(
|
||||
width: 20,
|
||||
customTexture:
|
||||
BitmapDescriptor.fromIconPath('assets/texture_green.png'),
|
||||
joinType: JoinType.round,
|
||||
points: _createPoints());
|
||||
|
||||
setState(() {
|
||||
_polylines[polyline.id] = polyline;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final AMapWidget map = AMapWidget(
|
||||
onMapCreated: _onMapCreated,
|
||||
polylines: Set<Polyline>.of(_polylines.values),
|
||||
);
|
||||
|
||||
return Container(
|
||||
height: MediaQuery.of(context).size.height,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 10,
|
||||
child: map,
|
||||
),
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: TextButton(
|
||||
onPressed: _add,
|
||||
style: ButtonStyle(
|
||||
shape: MaterialStateProperty.all(RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10))),
|
||||
//文字颜色
|
||||
foregroundColor: MaterialStateProperty.all(Colors.white),
|
||||
//水波纹颜色
|
||||
overlayColor: MaterialStateProperty.all(Colors.blueAccent),
|
||||
//背景颜色
|
||||
backgroundColor: MaterialStateProperty.resolveWith((states) {
|
||||
//设置按下时的背景颜色
|
||||
if (states.contains(MaterialState.pressed)) {
|
||||
return Colors.blueAccent;
|
||||
}
|
||||
//默认背景颜色
|
||||
return Colors.blue;
|
||||
}),
|
||||
),
|
||||
child: Text('添加纹理线'),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
40
example/lib/widgets/amap_gridview.dart
Normal file
40
example/lib/widgets/amap_gridview.dart
Normal file
@ -0,0 +1,40 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AMapGradView extends StatefulWidget {
|
||||
///子控件列表
|
||||
final List<Widget> childrenWidgets;
|
||||
|
||||
///一行的数量
|
||||
final int? crossAxisCount;
|
||||
|
||||
///宽高比
|
||||
final double? childAspectRatio;
|
||||
|
||||
AMapGradView(
|
||||
{Key? key,
|
||||
this.crossAxisCount,
|
||||
this.childAspectRatio,
|
||||
required this.childrenWidgets})
|
||||
: super(key: key);
|
||||
@override
|
||||
_GradViewState createState() => _GradViewState();
|
||||
}
|
||||
|
||||
class _GradViewState extends State<AMapGradView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GridView.count(
|
||||
primary: false,
|
||||
physics: new NeverScrollableScrollPhysics(),
|
||||
//水平子Widget之间间距
|
||||
crossAxisSpacing: 1.0,
|
||||
//垂直子Widget之间间距
|
||||
mainAxisSpacing: 0.5,
|
||||
//一行的Widget数量
|
||||
crossAxisCount: widget.crossAxisCount ?? 2,
|
||||
//宽高比
|
||||
childAspectRatio: widget.childAspectRatio ?? 4,
|
||||
children: widget.childrenWidgets,
|
||||
shrinkWrap: true);
|
||||
}
|
||||
}
|
77
example/lib/widgets/amap_radio_group.dart
Normal file
77
example/lib/widgets/amap_radio_group.dart
Normal file
@ -0,0 +1,77 @@
|
||||
import 'package:amap_map_example/widgets/amap_gridview.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AMapRadioGroup<T> extends StatefulWidget {
|
||||
final String? groupLabel;
|
||||
final T? groupValue;
|
||||
final Map<String, T>? radioValueMap;
|
||||
final ValueChanged<T>? onChanged;
|
||||
AMapRadioGroup(
|
||||
{Key? key,
|
||||
this.groupLabel,
|
||||
this.groupValue,
|
||||
this.radioValueMap,
|
||||
this.onChanged})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_AMapRadioGroupState createState() => _AMapRadioGroupState();
|
||||
}
|
||||
|
||||
class _AMapRadioGroupState extends State<AMapRadioGroup> {
|
||||
dynamic _groupValue;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_groupValue = widget.groupValue ?? null;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
List<Widget> radioList = <Widget>[];
|
||||
_groupValue = widget.groupValue ?? null;
|
||||
Widget _myRadio(String label, dynamic radioValue) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(label),
|
||||
Radio<dynamic>(
|
||||
value: radioValue,
|
||||
groupValue: _groupValue,
|
||||
onChanged: (_value) {
|
||||
setState(() {
|
||||
_groupValue = _value;
|
||||
});
|
||||
if (null != widget.onChanged) {
|
||||
widget.onChanged!(_value);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.radioValueMap != null) {
|
||||
widget.radioValueMap!.forEach((key, value) {
|
||||
radioList.add(_myRadio(key, value));
|
||||
});
|
||||
}
|
||||
return Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(widget.groupLabel!),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: AMapGradView(
|
||||
childrenWidgets: radioList,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
57
example/lib/widgets/amap_switch_button.dart
Normal file
57
example/lib/widgets/amap_switch_button.dart
Normal file
@ -0,0 +1,57 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
typedef void OnChanged(bool value);
|
||||
|
||||
class AMapSwitchButton extends StatefulWidget {
|
||||
const AMapSwitchButton({
|
||||
Key? key,
|
||||
this.label,
|
||||
this.onSwitchChanged,
|
||||
this.defaultValue = true,
|
||||
}) : super(key: key);
|
||||
|
||||
final Text? label;
|
||||
final Function? onSwitchChanged;
|
||||
final bool defaultValue;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _SwitchButtonState();
|
||||
}
|
||||
|
||||
class _SwitchButtonState extends State<AMapSwitchButton> {
|
||||
late bool _localValue;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_localValue = widget.defaultValue;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Container(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
widget.label!,
|
||||
Switch(
|
||||
value: _localValue,
|
||||
onChanged: (null != widget.onSwitchChanged)
|
||||
? (value) {
|
||||
setState(() {
|
||||
_localValue = value;
|
||||
});
|
||||
widget.onSwitchChanged!(value);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
70
example/lib/widgets/demo_group.dart
Normal file
70
example/lib/widgets/demo_group.dart
Normal file
@ -0,0 +1,70 @@
|
||||
import 'package:amap_map_example/base_page.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DemoGroupWidget extends StatefulWidget {
|
||||
final String groupLabel;
|
||||
final List<BasePage>? itemPages;
|
||||
|
||||
DemoGroupWidget({Key? key, required this.groupLabel, this.itemPages})
|
||||
: super(key: key);
|
||||
@override
|
||||
State<StatefulWidget> createState() => _GroupState();
|
||||
}
|
||||
|
||||
class _GroupState extends State<DemoGroupWidget> {
|
||||
void _pushPage(BuildContext context, BasePage page) {
|
||||
Navigator.of(context).push(MaterialPageRoute<void>(
|
||||
builder: (_) => Scaffold(
|
||||
appBar: AppBar(title: Text(page.title)),
|
||||
body: page,
|
||||
)));
|
||||
}
|
||||
|
||||
bool _hasItemPages = false;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.itemPages != null && widget.itemPages!.length > 0) {
|
||||
_hasItemPages = true;
|
||||
} else {
|
||||
_hasItemPages = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ListTile(
|
||||
title: Text(
|
||||
widget.groupLabel,
|
||||
style: TextStyle(fontWeight: FontWeight.w600, fontSize: 18),
|
||||
)),
|
||||
Divider(height: 1),
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: _hasItemPages
|
||||
? ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemCount: widget.itemPages!.length,
|
||||
itemBuilder: (_, int index) => ListTile(
|
||||
title: Text(widget.itemPages![index].title),
|
||||
subtitle: Text(widget.itemPages![index].subTitle),
|
||||
onTap: () => _pushPage(context, widget.itemPages![index]),
|
||||
),
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
Divider(
|
||||
height: 1,
|
||||
indent: 16,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
Divider(height: 1),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
136
example/lib/widgets/toast.dart
Normal file
136
example/lib/widgets/toast.dart
Normal file
@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
//Toast 显示位置控制
|
||||
enum ToastPostion {
|
||||
top,
|
||||
center,
|
||||
bottom,
|
||||
}
|
||||
|
||||
class Toast {
|
||||
// toast靠它加到屏幕上
|
||||
static OverlayEntry? _overlayEntry;
|
||||
// toast是否正在showing
|
||||
static bool _showing = false;
|
||||
// 开启一个新toast的当前时间,用于对比是否已经展示了足够时间
|
||||
static DateTime? _startedTime;
|
||||
// 提示内容
|
||||
static String? _msg;
|
||||
// toast显示时间
|
||||
static int _showTime = 10;
|
||||
// 背景颜色
|
||||
static Color? _bgColor;
|
||||
// 文本颜色
|
||||
static Color? _textColor;
|
||||
// 文字大小
|
||||
static double? _textSize;
|
||||
// 显示位置
|
||||
static ToastPostion? _toastPosition;
|
||||
// 左右边距
|
||||
static double? _pdHorizontal;
|
||||
// 上下边距
|
||||
static double? _pdVertical;
|
||||
static void toast(
|
||||
BuildContext context, {
|
||||
//显示的文本
|
||||
String? msg,
|
||||
//显示的时间 单位毫秒
|
||||
int showTime = 1000,
|
||||
//显示的背景
|
||||
Color bgColor = Colors.black,
|
||||
//显示的文本颜色
|
||||
Color textColor = Colors.white,
|
||||
//显示的文字大小
|
||||
double textSize = 14.0,
|
||||
//显示的位置
|
||||
ToastPostion position = ToastPostion.center,
|
||||
//文字水平方向的内边距
|
||||
double pdHorizontal = 20.0,
|
||||
//文字垂直方向的内边距
|
||||
double pdVertical = 10.0,
|
||||
}) async {
|
||||
assert(msg != null);
|
||||
_msg = msg;
|
||||
_startedTime = DateTime.now();
|
||||
_showTime = showTime;
|
||||
_bgColor = bgColor;
|
||||
_textColor = textColor;
|
||||
_textSize = textSize;
|
||||
_toastPosition = position;
|
||||
_pdHorizontal = pdHorizontal;
|
||||
_pdVertical = pdVertical;
|
||||
//获取OverlayState
|
||||
OverlayState overlayState = Overlay.of(context)!;
|
||||
_showing = true;
|
||||
if (_overlayEntry == null) {
|
||||
//OverlayEntry负责构建布局
|
||||
//通过OverlayEntry将构建的布局插入到整个布局的最上层
|
||||
_overlayEntry = OverlayEntry(
|
||||
builder: (BuildContext context) => Positioned(
|
||||
//top值,可以改变这个值来改变toast在屏幕中的位置
|
||||
top: buildToastPosition(context),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 40.0),
|
||||
child: AnimatedOpacity(
|
||||
opacity: _showing ? 1.0 : 0.0, //目标透明度
|
||||
duration: _showing
|
||||
? Duration(milliseconds: 100)
|
||||
: Duration(milliseconds: 400),
|
||||
child: _buildToastWidget(),
|
||||
),
|
||||
)),
|
||||
));
|
||||
//插入到整个布局的最上层
|
||||
overlayState.insert(_overlayEntry!);
|
||||
} else {
|
||||
//重新绘制UI,类似setState
|
||||
_overlayEntry!.markNeedsBuild();
|
||||
}
|
||||
// 等待时间
|
||||
await Future.delayed(Duration(milliseconds: _showTime));
|
||||
//2秒后 到底消失不消失
|
||||
if (DateTime.now().difference(_startedTime!).inMilliseconds >= _showTime) {
|
||||
_showing = false;
|
||||
_overlayEntry!.markNeedsBuild();
|
||||
await Future.delayed(Duration(milliseconds: 400));
|
||||
_overlayEntry!.remove();
|
||||
_overlayEntry = null;
|
||||
}
|
||||
}
|
||||
|
||||
//toast绘制
|
||||
static _buildToastWidget() {
|
||||
return Center(
|
||||
child: Card(
|
||||
color: _bgColor,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: _pdHorizontal!, vertical: _pdVertical!),
|
||||
child: Text(
|
||||
_msg!,
|
||||
style: TextStyle(
|
||||
fontSize: _textSize,
|
||||
color: _textColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 设置toast位置
|
||||
static buildToastPosition(context) {
|
||||
var backResult;
|
||||
if (_toastPosition == ToastPostion.top) {
|
||||
backResult = MediaQuery.of(context).size.height * 1 / 4;
|
||||
} else if (_toastPosition == ToastPostion.center) {
|
||||
backResult = MediaQuery.of(context).size.height * 2 / 5;
|
||||
} else {
|
||||
backResult = MediaQuery.of(context).size.height * 3 / 4;
|
||||
}
|
||||
return backResult;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user