重构example项目结构

This commit is contained in:
Kuloud 2023-12-30 07:54:59 +08:00
parent f8e58fcb35
commit 5abe4d7f6d
30 changed files with 740 additions and 547 deletions

View File

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
class AnimatedCategoryItem extends StatelessWidget {
AnimatedCategoryItem({
required double startDelayFraction,
required this.controller,
required this.child,
}) : topPaddingAnimation = Tween(
begin: 0.0,
end: 16.0,
).animate(
CurvedAnimation(
parent: controller,
curve: Interval(
0.000 + startDelayFraction,
0.400 + startDelayFraction,
curve: Curves.ease,
),
),
);
final Widget child;
final AnimationController controller;
final Animation<double> topPaddingAnimation;
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: controller,
builder: (context, child) {
return Padding(
padding: EdgeInsets.only(top: topPaddingAnimation.value),
child: child,
);
},
child: child,
);
}
}

View File

@ -1,9 +0,0 @@
import 'package:flutter/cupertino.dart';
///demo的模板类
abstract class BasePage extends StatelessWidget {
final String title;
final String subTitle;
const BasePage(this.title, this.subTitle);
}

View File

@ -0,0 +1,319 @@
import 'package:amap_map_example/main.dart';
import 'package:flutter/material.dart';
typedef CategoryHeaderTapCallback = Function(bool shouldOpenList);
class CategoryListItem extends StatefulWidget {
const CategoryListItem({
super.key,
this.restorationId,
required this.category,
this.demos = const [],
this.initiallyExpanded = false,
this.onTap,
});
final DemoCategory category;
final String? restorationId;
final List<Demo> demos;
final bool initiallyExpanded;
final CategoryHeaderTapCallback? onTap;
@override
State<CategoryListItem> createState() => _CategoryListItemState();
}
class _CategoryListItemState extends State<CategoryListItem>
with SingleTickerProviderStateMixin {
static final Animatable<double> _easeInTween =
CurveTween(curve: Curves.easeIn);
static const _expandDuration = Duration(milliseconds: 200);
late AnimationController _controller;
late Animation<double> _childrenHeightFactor;
late Animation<double> _headerChevronOpacity;
late Animation<double> _headerHeight;
late Animation<EdgeInsetsGeometry> _headerMargin;
late Animation<EdgeInsetsGeometry> _headerImagePadding;
late Animation<EdgeInsetsGeometry> _childrenPadding;
late Animation<BorderRadius?> _headerBorderRadius;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: _expandDuration, vsync: this);
_controller.addStatusListener((status) {
setState(() {});
});
_childrenHeightFactor = _controller.drive(_easeInTween);
_headerChevronOpacity = _controller.drive(_easeInTween);
_headerHeight = Tween<double>(
begin: 80,
end: 96,
).animate(_controller);
_headerMargin = EdgeInsetsGeometryTween(
begin: const EdgeInsets.fromLTRB(32, 8, 32, 8),
end: EdgeInsets.zero,
).animate(_controller);
_headerImagePadding = EdgeInsetsGeometryTween(
begin: const EdgeInsets.all(8),
end: const EdgeInsetsDirectional.fromSTEB(16, 8, 8, 8),
).animate(_controller);
_childrenPadding = EdgeInsetsGeometryTween(
begin: const EdgeInsets.symmetric(horizontal: 32),
end: EdgeInsets.zero,
).animate(_controller);
_headerBorderRadius = BorderRadiusTween(
begin: BorderRadius.circular(10),
end: BorderRadius.zero,
).animate(_controller);
if (widget.initiallyExpanded) {
_controller.value = 1.0;
}
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
bool _shouldOpenList() {
switch (_controller.status) {
case AnimationStatus.completed:
case AnimationStatus.forward:
return false;
case AnimationStatus.dismissed:
case AnimationStatus.reverse:
return true;
}
}
void _handleTap() {
if (_shouldOpenList()) {
_controller.forward();
if (widget.onTap != null) {
widget.onTap!(true);
}
} else {
_controller.reverse();
if (widget.onTap != null) {
widget.onTap!(false);
}
}
}
Widget _buildHeaderWithChildren(BuildContext context, Widget? child) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
_CategoryHeader(
margin: _headerMargin.value,
imagePadding: _headerImagePadding.value,
borderRadius: _headerBorderRadius.value!,
height: _headerHeight.value,
chevronOpacity: _headerChevronOpacity.value,
category: widget.category,
onTap: _handleTap,
),
Padding(
padding: _childrenPadding.value,
child: ClipRect(
child: Align(
heightFactor: _childrenHeightFactor.value,
child: child,
),
),
),
],
);
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller.view,
builder: _buildHeaderWithChildren,
child: _shouldOpenList()
? null
: _ExpandedCategoryDemos(
category: widget.category,
demos: widget.demos,
),
);
}
}
class _CategoryHeader extends StatelessWidget {
const _CategoryHeader({
this.margin,
required this.imagePadding,
required this.borderRadius,
this.height,
required this.chevronOpacity,
required this.category,
this.onTap,
});
final EdgeInsetsGeometry? margin;
final EdgeInsetsGeometry imagePadding;
final double? height;
final BorderRadiusGeometry borderRadius;
final DemoCategory category;
final double chevronOpacity;
final GestureTapCallback? onTap;
@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Container(
margin: margin,
child: Material(
shape: RoundedRectangleBorder(borderRadius: borderRadius),
color: colorScheme.onBackground,
clipBehavior: Clip.antiAlias,
child: SizedBox(
width: MediaQuery.of(context).size.width,
child: InkWell(
// Makes integration tests possible.
key: ValueKey('${category.name}CategoryHeader'),
onTap: onTap,
child: Row(
children: [
Expanded(
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Padding(
padding: imagePadding,
child: ExcludeSemantics(
child: SizedBox(
height: 48, // icon placeholder
),
),
),
Padding(
padding: const EdgeInsetsDirectional.only(start: 8),
child: Text(
category.toDisplayTitle(),
style: Theme.of(context).textTheme.headline5!.apply(
color: colorScheme.onSurface,
),
),
),
],
),
),
Opacity(
opacity: chevronOpacity,
child: chevronOpacity != 0
? Padding(
padding: const EdgeInsetsDirectional.only(
start: 8,
end: 32,
),
child: Icon(
Icons.keyboard_arrow_up,
color: colorScheme.onSurface,
),
)
: null,
),
],
),
),
),
),
);
}
}
class _ExpandedCategoryDemos extends StatelessWidget {
const _ExpandedCategoryDemos({
required this.category,
required this.demos,
});
final DemoCategory category;
final List<Demo> demos;
@override
Widget build(BuildContext context) {
return Column(
// Makes integration tests possible.
key: ValueKey('${category.name}DemoList'),
children: [
for (final demo in demos)
CategoryDemoItem(
demo: demo,
),
const SizedBox(height: 12), // Extra space below.
],
);
}
}
class CategoryDemoItem extends StatelessWidget {
const CategoryDemoItem({super.key, required this.demo});
final Demo demo;
@override
Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme;
final colorScheme = Theme.of(context).colorScheme;
return Material(
// Makes integration tests possible.
key: ValueKey(demo.describe),
color: Theme.of(context).colorScheme.surface,
child: MergeSemantics(
child: InkWell(
onTap: () {
Navigator.of(context).restorablePushNamed(
'/${demo.slug}',
);
},
child: Padding(
padding: EdgeInsetsDirectional.only(
start: 32,
top: 20,
end: 8,
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(width: 40),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
demo.title,
style: textTheme.subtitle1!
.apply(color: colorScheme.onSurface),
),
Text(
demo.subtitle,
style: textTheme.overline!.apply(
color: colorScheme.onSurface.withOpacity(0.5),
),
),
const SizedBox(height: 20),
Divider(
thickness: 1,
height: 1,
color: Theme.of(context).colorScheme.background,
),
],
),
),
],
),
),
),
),
);
}
}

View File

@ -0,0 +1,81 @@
import 'dart:collection';
import 'package:amap_map_example/main.dart';
import 'package:amap_map_example/pages/interactive/map_ui_options.dart';
import 'package:amap_map_example/pages/map/limit_map_bounds.dart';
import 'package:amap_map_example/pages/map/map_my_location.dart';
import 'package:amap_map_example/pages/map/show_map_page.dart';
import 'package:amap_map_example/pages/overlays/marker_config.dart';
import 'package:flutter/material.dart';
class DemoConfiguration {
const DemoConfiguration({
required this.buildRoute,
});
final WidgetBuilder buildRoute;
}
List<Demo> allDemos() => mapDemos() + interactiveDemos() + overlayDemos();
List<Demo> mapDemos() {
return [
Demo(
title: '显示地图',
category: DemoCategory.basic,
subtitle: '基本地图显示',
slug: 'show-map',
configurations: [
DemoConfiguration(buildRoute: (context) => ShowMapPage())
]),
Demo(
title: '显示定位蓝点',
category: DemoCategory.basic,
subtitle: '定位蓝点指的是进入地图后显示当前位置点的功能',
slug: 'my-location',
configurations: [
DemoConfiguration(buildRoute: (context) => LimitMapBoundsPage())
]),
Demo(
title: '限制地图显示范围',
category: DemoCategory.basic,
subtitle: '演示限定手机屏幕显示地图的范围',
slug: 'limit-map-bounds',
configurations: [
DemoConfiguration(buildRoute: (context) => MyLocationPage())
]),
];
}
List<Demo> interactiveDemos() {
return [
Demo(
title: 'UI控制',
category: DemoCategory.interactive,
subtitle: '浮在地图图面上用于操作地图的组件,例如缩放按钮、指南针、定位按钮、比例尺等。',
slug: 'map-ui',
configurations: [
DemoConfiguration(buildRoute: (context) => MapUIDemoPage())
])
];
}
List<Demo> overlayDemos() {
return [
Demo(
title: '绘制点标记',
category: DemoCategory.overlay,
subtitle: '演示Marker的相关属性的操作',
slug: 'marker-config',
configurations: [
DemoConfiguration(buildRoute: (context) => MarkerConfigDemoPage())
])
];
}
Map<String?, Demo> slugToDemo(BuildContext context) {
return LinkedHashMap<String?, Demo>.fromIterable(
allDemos(),
key: (dynamic demo) => demo.slug as String?,
);
}

68
example/lib/demo.dart Normal file
View File

@ -0,0 +1,68 @@
import 'package:amap_map_example/data/demos.dart';
import 'package:amap_map_example/main.dart';
import 'package:flutter/material.dart';
class DemoPage extends StatefulWidget {
const DemoPage({
super.key,
required this.slug,
});
final String? slug;
@override
State<DemoPage> createState() => _DemoPageState();
}
class _DemoPageState extends State<DemoPage> {
late Map<String?, Demo> slugToDemoMap;
@override
void didChangeDependencies() {
super.didChangeDependencies();
slugToDemoMap = slugToDemo(context);
}
@override
Widget build(BuildContext context) {
if (widget.slug == null || !slugToDemoMap.containsKey(widget.slug)) {
// Return to root if invalid slug.
Navigator.of(context).pop();
}
return ScaffoldMessenger(
child: AMapDemoPage(
restorationId: widget.slug!,
demo: slugToDemoMap[widget.slug]!,
));
}
}
class AMapDemoPage extends StatefulWidget {
const AMapDemoPage({
super.key,
required this.restorationId,
required this.demo,
});
final String restorationId;
final Demo demo;
@override
State<StatefulWidget> createState() => _AMapDemoPageState(demo);
}
class _AMapDemoPageState extends State<AMapDemoPage> {
_AMapDemoPageState(this.demo);
final Demo demo;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(demo.title)),
body: SafeArea(
child: Builder(builder: demo.configurations.first.buildRoute),
),
);
}
}

View File

@ -1,64 +1,42 @@
import 'package:amap_map/amap_map.dart';
import 'package:amap_map_example/animated_category_item.dart';
import 'package:amap_map_example/category_list_item.dart';
import 'package:amap_map_example/const_config.dart';
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:amap_map_example/data/demos.dart';
import 'package:amap_map_example/routes.dart';
import 'package:amap_map_example/theme.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'base_page.dart';
// final List<BasePage> _mapDemoPages = <BasePage>[
// AllMapConfigDemoPage('总体演示', '演示AMapWidget的所有配置项'),
final List<BasePage> _mapDemoPages = <BasePage>[
AllMapConfigDemoPage('总体演示', '演示AMapWidget的所有配置项'),
ShowMapPage('显示地图', '基本地图显示'),
LimitMapBoundsPage('限制地图显示范围', '演示限定手机屏幕显示地图的范围'),
MinMaxZoomDemoPage('指定显示级别范围', '演示指定最小最大级别功能'),
ChangeMapTypePage('切换地图图层', '演示内置的地图图层'),
CustomMapStylePage('自定义地图', '根据自定义的地图样式文件显示地图'),
MultiMapDemoPage('地图多实例', '同时显示多个地图'),
];
// MinMaxZoomDemoPage('指定显示级别范围', '演示指定最小最大级别功能'),
// ChangeMapTypePage('切换地图图层', '演示内置的地图图层'),
// CustomMapStylePage('自定义地图', '根据自定义的地图样式文件显示地图'),
// MultiMapDemoPage('地图多实例', '同时显示多个地图'),
// ];
final List<BasePage> _interactiveDemoPages = <BasePage>[
MapUIDemoPage('UI控制', 'ui开关演示'),
GesturesDemoPage('手势交互', '手势交互'),
PoiClickDemoPage('点击poi功能', '演示点击poi之后的回调和信息透出'),
MoveCameraDemoPage('改变地图视角', '演示改变地图的中心点、可视区域、缩放级别等功能'),
SnapshotPage('地图截屏', '地图截屏示例'),
MyLocationPage('显示我的位置', '在地图上显示我的位置'),
];
// final List<BasePage> _interactiveDemoPages = <BasePage>[
// MapUIDemoPage('UI控制', 'ui开关演示'),
// GesturesDemoPage('手势交互', '手势交互'),
// PoiClickDemoPage('点击poi功能', '演示点击poi之后的回调和信息透出'),
// MoveCameraDemoPage('改变地图视角', '演示改变地图的中心点、可视区域、缩放级别等功能'),
// SnapshotPage('地图截屏', '地图截屏示例'),
// ];
final List<BasePage> _markerPages = <BasePage>[
MarkerConfigDemoPage('Marker操作', '演示Marker的相关属性的操作'),
MarkerAddWithMapPage("随地图添加", "演示初始化地图时直接添加marker"),
MarkerAddAfterMapPage("单独添加", "演示地图初始化之后单独添加marker功能"),
MarkerCustomIconPage('自定义图标', '演示marker使用自定义图标功能'),
];
// final List<BasePage> _markerPages = <BasePage>[
// MarkerAddWithMapPage("随地图添加", "演示初始化地图时直接添加marker"),
// MarkerAddAfterMapPage("单独添加", "演示地图初始化之后单独添加marker功能"),
// MarkerCustomIconPage('自定义图标', '演示marker使用自定义图标功能'),
// ];
final List<BasePage> _overlayPages = <BasePage>[
PolylineDemoPage('Polyline操作', '演示Polyline的相关属性的操作'),
PolylineGeodesicDemoPage('Polyline大地曲线', '演示大地曲线的添加'),
PolylineTextureDemoPage('Polyline纹理线', '演示纹理线的添加'),
PolygonDemoPage('Polygon操作', '演示Polygon的相关属性的操作'),
];
// final List<BasePage> _overlayPages = <BasePage>[
// PolylineDemoPage('Polyline操作', '演示Polyline的相关属性的操作'),
// PolylineGeodesicDemoPage('Polyline大地曲线', '演示大地曲线的添加'),
// PolylineTextureDemoPage('Polyline纹理线', '演示纹理线的添加'),
// PolygonDemoPage('Polygon操作', '演示Polygon的相关属性的操作'),
// ];
final List<Permission> needPermissionList = [
Permission.location,
@ -68,17 +46,24 @@ final List<Permission> needPermissionList = [
class AMapDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return DemoWidget();
}
State<StatefulWidget> createState() => _AMapDemoState();
}
class DemoWidget extends State<AMapDemo> {
class _AMapDemoState extends State<AMapDemo>
with RestorationMixin, SingleTickerProviderStateMixin {
late AnimationController _animationController;
final RestorableBool _isMapListExpanded = RestorableBool(false);
@override
void initState() {
super.initState();
_checkPermissions();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 800),
);
}
@override
@ -101,41 +86,83 @@ class DemoWidget extends State<AMapDemo> {
AMapInitializer.updatePrivacyAgree(ConstConfig.amapPrivacyStatement);
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,
),
],
),
),
),
body: ListView(
children: [
AnimatedCategoryItem(
startDelayFraction: 0,
controller: _animationController,
child: CategoryListItem(
category: DemoCategory.basic,
demos: mapDemos(),
)),
AnimatedCategoryItem(
startDelayFraction: 0.05,
controller: _animationController,
child: CategoryListItem(
category: DemoCategory.interactive,
demos: interactiveDemos(),
)),
AnimatedCategoryItem(
startDelayFraction: 0.1,
controller: _animationController,
child: CategoryListItem(
category: DemoCategory.overlay,
demos: overlayDemos(),
)),
],
),
);
}
@override
String? get restorationId => 'demos';
@override
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
registerForRestoration(_isMapListExpanded, 'map_list');
}
}
void main() {
// debugProfileBuildsEnabled = true;
// debugProfilePaintsEnabled = true;
// debugPaintLayerBordersEnabled = true;
runApp(MaterialApp(home: AMapDemo()));
runApp(MaterialApp(
theme: ThemeData(colorScheme: DemoThemeData.lightColorScheme),
themeMode: ThemeMode.light,
onGenerateRoute: RouteConfig.onGenerateRoute,
home: AMapDemo()));
}
enum DemoCategory {
basic,
interactive,
overlay;
String toDisplayTitle() {
switch (this) {
case basic:
return '创建地图';
case interactive:
return '与地图交互';
case overlay:
return '在地图上绘制';
}
}
}
class Demo {
const Demo({
required this.title,
required this.category,
required this.subtitle,
// Parameters below are required for non-study demos.
this.slug,
this.configurations = const [],
}) : assert(slug != null);
final String title;
final DemoCategory category;
final String subtitle;
final String? slug;
final List<DemoConfiguration> configurations;
String get describe => '$slug@${category.name}';
}

View File

@ -1,14 +0,0 @@
// 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;
}

View File

@ -1,24 +1,16 @@
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);
class GesturesDemoPage extends StatefulWidget {
GesturesDemoPage({Key? key}) : super(key: key);
@override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<_Body> {
class _BodyState extends State<GesturesDemoPage> {
///
bool _zoomGesturesEnabled = true;

View File

@ -1,25 +1,16 @@
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);
class MapUIDemoPage extends StatefulWidget {
MapUIDemoPage({Key? key}) : super(key: key);
@override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<_Body> {
class _BodyState extends State<MapUIDemoPage> {
///
bool _trafficEnabled = false;

View File

@ -1,24 +1,14 @@
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 {
class SnapshotPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _SnapShotState();
}
class _SnapShotState extends State<_SnapShotBody> {
class _SnapShotState extends State<SnapshotPage> {
AMapController? _mapController;
Uint8List? _imageBytes;
@override

View File

@ -1,24 +1,15 @@
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);
class ChangeMapTypePage extends StatefulWidget {
ChangeMapTypePage({Key? key}) : super(key: key);
@override
_PageBodyState createState() => _PageBodyState();
}
class _PageBodyState extends State<_PageBody> {
class _PageBodyState extends State<ChangeMapTypePage> {
//
late MapType _mapType;
final Map<String, MapType> _radioValueMap = {

View File

@ -1,27 +1,16 @@
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);
class CustomMapStylePage extends StatefulWidget {
CustomMapStylePage({Key? key}) : super(key: key);
@override
_CustomMapStyleState createState() => _CustomMapStyleState();
}
class _CustomMapStyleState extends State<_CustomMapStyleBody> {
class _CustomMapStyleState extends State<CustomMapStylePage> {
bool _mapCreated = false;
CustomStyleOptions _customStyleOptions = CustomStyleOptions(false);

View File

@ -1,24 +1,15 @@
import 'package:amap_map/amap_map.dart';
import 'package:x_amap_base/x_amap_base.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);
class LimitMapBoundsPage extends StatefulWidget {
LimitMapBoundsPage({Key? key}) : super(key: key);
@override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<_Body> {
class _BodyState extends State<LimitMapBoundsPage> {
@override
Widget build(BuildContext context) {
final AMapWidget amap = AMapWidget(

View File

@ -1,28 +1,18 @@
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:x_amap_base/x_amap_base.dart';
class AllMapConfigDemoPage extends BasePage {
AllMapConfigDemoPage(String title, String subTitle) : super(title, subTitle);
@override
Widget build(BuildContext context) {
return _MapUiBody();
}
}
class _MapUiBody extends StatefulWidget {
class AllMapConfigDemoPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _MapUiBodyState();
}
class _MapUiBodyState extends State<_MapUiBody> {
class _MapUiBodyState extends State<AllMapConfigDemoPage> {
//
static final CameraPosition _kInitialPosition = const CameraPosition(
target: LatLng(39.909187, 116.397451),

View File

@ -1,22 +1,14 @@
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);
class MyLocationPage extends StatefulWidget {
MyLocationPage({Key? key}) : super(key: key);
@override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<_Body> {
class _BodyState extends State<MyLocationPage> {
@override
void initState() {
super.initState();
@ -44,6 +36,7 @@ class _BodyState extends State<_Body> {
circleStrokeWidth: 1,
),
);
return Container(
child: amap,
);

View File

@ -1,23 +1,14 @@
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);
class MinMaxZoomDemoPage extends StatefulWidget {
MinMaxZoomDemoPage({Key? key}) : super(key: key);
@override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<_Body> {
class _BodyState extends State<MinMaxZoomDemoPage> {
final double _minZoom = 10;
final double _maxZoom = 15;
String? _currentZoom;

View File

@ -1,23 +1,14 @@
import 'package:amap_map/amap_map.dart';
import 'package:x_amap_base/x_amap_base.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();
class MultiMapDemoPage extends StatefulWidget {
const MultiMapDemoPage();
@override
State<StatefulWidget> createState() => _MultiMapDemoState();
}
class _MultiMapDemoState extends State<_MultiMapDemoBody> {
class _MultiMapDemoState extends State<MultiMapDemoPage> {
@override
Widget build(BuildContext context) {
return Container(

View File

@ -1,23 +1,13 @@
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 {
class ShowMapPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ShowMapPageState();
}
class _ShowMapPageState extends State<_ShowMapPageBody> {
class _ShowMapPageState extends State<ShowMapPage> {
List<Widget> _approvalNumberWidget = <Widget>[];
@override
Widget build(BuildContext context) {

View File

@ -1,22 +1,13 @@
import 'package:amap_map/amap_map.dart';
import 'package:x_amap_base/x_amap_base.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 {
class MarkerAddAfterMapPage extends StatefulWidget {
@override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<_Body> {
class _BodyState extends State<MarkerAddAfterMapPage> {
static final LatLng defaultPosition = const LatLng(39.909187, 116.397451);
//map赋值给AMapWidget的markersmarker
final Map<String, Marker> _markers = <String, Marker>{};

View File

@ -2,23 +2,14 @@ import 'dart:math';
import 'package:amap_map/amap_map.dart';
import 'package:x_amap_base/x_amap_base.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 {
class MarkerAddWithMapPage extends StatefulWidget {
@override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<_Body> {
class _BodyState extends State<MarkerAddWithMapPage> {
static final LatLng mapCenter = const LatLng(39.909187, 116.397451);
final Map<String, Marker> _initMarkerMap = <String, Marker>{};

View File

@ -2,33 +2,21 @@ 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:x_amap_base/x_amap_base.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();
class MarkerConfigDemoPage extends StatefulWidget {
const MarkerConfigDemoPage();
@override
State<StatefulWidget> createState() => _State();
}
class _State extends State<_Body> {
class _State extends State<MarkerConfigDemoPage> {
static final LatLng mapCenter = const LatLng(39.909187, 116.397451);
Map<String, Marker> _markers = <String, Marker>{};

View File

@ -1,22 +1,13 @@
import 'package:amap_map/amap_map.dart';
import 'package:x_amap_base/x_amap_base.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 {
class MarkerCustomIconPage extends StatefulWidget {
@override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<_Body> {
class _BodyState extends State<MarkerCustomIconPage> {
static final LatLng markerPosition = const LatLng(39.909187, 116.397451);
final Map<String, Marker> _initMarkerMap = <String, Marker>{};
String? _currentMarkerId;

View File

@ -1,4 +1,3 @@
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';
@ -6,22 +5,14 @@ import 'package:flutter/widgets.dart';
import 'package:amap_map/amap_map.dart';
import 'package:x_amap_base/x_amap_base.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();
class PolygonDemoPage extends StatefulWidget {
const PolygonDemoPage();
@override
State<StatefulWidget> createState() => _State();
}
class _State extends State<_Body> {
class _State extends State<PolygonDemoPage> {
_State();
// Values when toggling Polygon color

View File

@ -1,4 +1,3 @@
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';
@ -6,22 +5,14 @@ import 'package:flutter/widgets.dart';
import 'package:amap_map/amap_map.dart';
import 'package:x_amap_base/x_amap_base.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();
class PolylineDemoPage extends StatefulWidget {
const PolylineDemoPage();
@override
State<StatefulWidget> createState() => _State();
}
class _State extends State<_Body> {
class _State extends State<PolylineDemoPage> {
_State();
// Values when toggling polyline color

View File

@ -1,27 +1,17 @@
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:x_amap_base/x_amap_base.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();
class PolylineGeodesicDemoPage extends StatefulWidget {
const PolylineGeodesicDemoPage();
@override
State<StatefulWidget> createState() => _State();
}
class _State extends State<_Body> {
class _State extends State<PolylineGeodesicDemoPage> {
_State();
// Values when toggling polyline color

View File

@ -1,27 +1,16 @@
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:x_amap_base/x_amap_base.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();
class PolylineTextureDemoPage extends StatefulWidget {
const PolylineTextureDemoPage();
@override
State<StatefulWidget> createState() => _State();
}
class _State extends State<_Body> {
class _State extends State<PolylineTextureDemoPage> {
_State();
Map<String, Polyline> _polylines = <String, Polyline>{};

47
example/lib/routes.dart Normal file
View File

@ -0,0 +1,47 @@
import 'package:amap_map_example/demo.dart';
import 'package:flutter/material.dart';
typedef PathWidgetBuilder = Widget Function(BuildContext, String?);
class Path {
const Path(this.pattern, this.builder);
/// A RegEx string for route matching.
final String pattern;
/// The builder for the associated pattern route. The first argument is the
/// [BuildContext] and the second argument a RegEx match if that is included
/// in the pattern.
///
/// ```dart
/// Path(
/// 'r'^/([\w-]+)$',
/// (context, matches) => Page(argument: match),
/// )
/// ```
final PathWidgetBuilder builder;
}
class RouteConfig {
static List<Path> _paths = [
Path(
r'^/([\w-]+)$',
(context, match) => DemoPage(slug: match),
),
];
static Route<dynamic>? onGenerateRoute(RouteSettings settings) {
for (final path in _paths) {
final regExpPattern = RegExp(path.pattern);
if (regExpPattern.hasMatch(settings.name!)) {
final firstMatch = regExpPattern.firstMatch(settings.name!)!;
final match = (firstMatch.groupCount == 1) ? firstMatch.group(1) : null;
return MaterialPageRoute<void>(
builder: (context) => path.builder(context, match),
settings: settings,
);
}
}
}
}

20
example/lib/theme.dart Normal file
View File

@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
class DemoThemeData {
static const _lightFillColor = Colors.black;
static const ColorScheme lightColorScheme = ColorScheme(
primary: Color(0xFFB93C5D),
primaryContainer: Color(0xFF117378),
secondary: Color(0xFFEFF3F3),
secondaryContainer: Color(0xFFFAFBFB),
background: Color(0xFFE6EBEB),
surface: Color(0xFFFAFBFB),
onBackground: Colors.white,
error: _lightFillColor,
onError: _lightFillColor,
onPrimary: _lightFillColor,
onSecondary: Color(0xFF322942),
onSurface: Color(0xFF241E30),
brightness: Brightness.light,
);
}

View File

@ -1,70 +0,0 @@
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),
],
);
}
}

View File

@ -1,136 +0,0 @@
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 {
//UIsetState
_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;
}
}