Compare commits

...

20 Commits

Author SHA1 Message Date
c4301dee85 chore: bump version to 1.0.15 and add new draw circle plugin files 2025-03-18 08:37:49 +08:00
df99810fdf chore: update dependencies in build.gradle 2025-03-18 08:37:24 +08:00
d4d248d714 Merge branch 'main' of https://github.com/kuloud/amap_map
# Conflicts:
#	android/build.gradle
#	pubspec.yaml
2025-03-18 08:21:02 +08:00
19c0c3bae6 chore: code lint 2025-03-12 11:03:18 +08:00
7cd7360eb8 doc: update readme 2025-03-12 10:18:04 +08:00
c11bc05d01 doc: 更新changelog文档 2025-03-12 00:29:59 +08:00
c66b8e1ebd release: 1.0.13 2025-03-12 00:01:15 +08:00
d08a83557d feat: update amap sdk version 2025-03-11 21:22:56 +08:00
9c16889c46 dispose 2024-11-29 18:57:40 +08:00
57c0602014 dispose 2024-11-29 18:57:24 +08:00
8dac5bc3b1 namespace 2024-11-19 17:23:45 +08:00
0a6e9c7119 release: 1.0.12 2024-08-26 09:55:49 +08:00
43ecfb8ca1 lint: code lint 2024-08-26 00:00:23 +08:00
8c59ec203a release: 1.0.11 2024-08-25 23:37:44 +08:00
74e60b2015 doc: update readme 2024-08-25 22:54:34 +08:00
ae87148c2c chore: append GIT_LOG 2024-08-25 22:49:30 +08:00
2a889ebbdf release: 1.0.10 2024-08-25 22:35:31 +08:00
9c1509c59d chore: add commit logs 2024-08-24 11:40:00 +08:00
e8e1a4d922 release: 1.0.9 2024-08-24 11:31:48 +08:00
4602f30730 release: 1.0.9, add map language support 2024-08-24 11:24:07 +08:00
78 changed files with 924 additions and 1107 deletions

View File

@ -19,6 +19,18 @@ jobs:
skipTests: true skipTests: true
flutter: true flutter: true
force: true force: true
- name: Get Commit Logs
id: git_log
run: |
TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$TAG" ]; then
GIT_LOG=$(git log --pretty=format:'- %s')
else
GIT_LOG=$(git log --pretty=format:'- %s' $TAG..HEAD)
fi
echo "git_log=$GIT_LOG" >> $GITHUB_ENV
- name: Create Release - name: Create Release
if: steps.package_publisher.outputs.success == 'true' if: steps.package_publisher.outputs.success == 'true'
uses: kuloud/Github-Release-Action@v1 uses: kuloud/Github-Release-Action@v1
@ -28,6 +40,8 @@ jobs:
tag_name: v${{ steps.package_publisher.outputs.localVersion }} tag_name: v${{ steps.package_publisher.outputs.localVersion }}
title: Release ${{ steps.package_publisher.outputs.localVersion }} title: Release ${{ steps.package_publisher.outputs.localVersion }}
body: | body: |
Automated release for version ${{ steps.package_publisher.outputs.localVersion }} Automated release for version ${{ steps.package_publisher.outputs.localVersion }}\n
Changes in this release:\n
${{ env.git_log }}
draft: false draft: false
prerelease: false prerelease: false

1
.gitignore vendored
View File

@ -10,3 +10,4 @@ build/
**/pubspec.lock **/pubspec.lock
.settings/ .settings/
.project .project
**.cxx

View File

@ -1,3 +1,35 @@
## 1.0.14
2025-03-12
* code lint
## 1.0.13
2025-03-11
* 升级amap android sdk版本 10.1.200_loc6.4.9_sea9.7.4 | 2025-03-11
* 升级amap iOS sdk版本 10.1.200 | 2024-12-26
* 修复问题android 构建异常,过期接口 io.flutter.view.FlutterMain 替换
* 修复问题android 构建异常,过期接口 PluginRegistry.Registrar 替换
## 1.0.12
2024-08-26
* code lint
## 1.0.11
2024-08-25
* 升级amap iOS sdk版本 10.0.900 | 2024-08-23
* code lint
## 1.0.10
2024-08-25
* 移除extension实现机制
* 添加 getMapContentApprovalNumber / getSatelliteImageApprovalNumber参见example#ShowMapPage
* 添加 InfoWindowAdapter参见example#CustomInfoWindowDemoPage,结合 infoWindowEnable 和 BaseInfoWindowAdapter 自行实现具体逻辑
* permission_handler 11.3.0 -> 11.3.1
## 1.0.9
2024-08-24
* 设置地图语言支持中文、英文按SDK描述1、不能和自定义地图样式同时使用2、英文状态只在标准地图生效
## 1.0.8 ## 1.0.8
2024-07-29. 2024-07-29.
* 升级amap android sdk版本 10.0.800_loc6.4.5_sea9.7.2 | 2024-07-19 * 升级amap android sdk版本 10.0.800_loc6.4.5_sea9.7.2 | 2024-07-19

View File

@ -6,7 +6,7 @@
| | Android | iOS | | | Android | iOS |
| ----------- | -------------------------- | -------- | | ----------- | -------------------------- | -------- |
| **AMapSDK** | 10.0.800_loc6.4.5_sea9.7.2 | 10.0.800 | | **AMapSDK** | 10.1.200_loc6.4.9_sea9.7.4 | 10.1.200 |
| **Support** | SDK 16+ | 12.0+ | | **Support** | SDK 16+ | 12.0+ |
本插件基于 amap_flutter_map 3.0.0 进行二开的原因: 本插件基于 amap_flutter_map 3.0.0 进行二开的原因:
@ -213,8 +213,11 @@ class AMapWidget extends StatefulWidget {
///需要应用到地图上的手势集合 ///需要应用到地图上的手势集合
final Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers; final Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers;
///拓展插件,提供更多定制化功能 /// 设置地图语言
final List<AMapExtension> extensions; final MapLanguage? mapLanguage;
/// Marker InfoWindow 适配器
final InfoWindowAdapter? infoWindowAdapter;
} }
``` ```
@ -266,4 +269,6 @@ class AMapController {
google 官方说明地址https://source.android.com/devices/tech/debug/tagged-pointers google 官方说明地址https://source.android.com/devices/tech/debug/tagged-pointers
2. 原本本插件拓展设计的思路是把一些不常用的特性功能做成可插拔的 extension昨天2024/07/28考虑了下觉得有点过度设计了包括轻量版 SDK 的接入适配,于是决定后续实现做些调整,尽量贴合 SDK API 实现功能。 1. 原本本插件拓展设计的思路是把一些不常用的特性功能做成可插拔的 extension昨天2024/07/28考虑了下觉得有点过度设计了包括轻量版 SDK 的接入适配,于是决定后续实现做些调整,尽量贴合 SDK API 实现功能。
1. 如果模拟器运行遇到 `com.amap.api.col.3sl.dl$b.createContext(GlesUtility.java:73)` 闪退,可尝试切换模拟器图像加速模式为`Software`以获得更好的兼容性。[Issue #27](https://github.com/kuloud/amap_map/issues/27)

21
analysis_options.yaml Normal file
View File

@ -0,0 +1,21 @@
include: package:flutter_lints/flutter.yaml
analyzer:
exclude:
- "**/*.g.dart"
- "**/*.freezed.dart"
errors:
missing_required_param: error
missing_return: error
invalid_null_aware_operator: error
linter:
rules:
always_specify_types: true
prefer_final_fields: true
prefer_final_in_for_each: true
prefer_const_constructors: true
prefer_const_declarations: true
avoid_print: false
avoid_empty_else: true
sort_child_properties_last: true

View File

@ -8,7 +8,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.5.3' classpath 'com.android.tools.build:gradle:3.5.4'
} }
} }
@ -22,7 +22,8 @@ rootProject.allprojects {
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
android { android {
compileSdkVersion 34 namespace = "com.amap.flutter.map"
compileSdkVersion 35
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
@ -33,7 +34,8 @@ android {
} }
dependencies { dependencies {
implementation 'com.amap.api:3dmap-location-search:10.0.800_loc6.4.5_sea9.7.2' // implementation 'com.amap.api:3dmap-location-search:10.1.200_loc6.4.9_sea9.7.4'
implementation 'androidx.annotation:annotation:1.8.1' implementation 'com.amap.api:navi-3dmap:latest.integration'
implementation 'androidx.annotation:annotation:1.9.1'
} }

View File

@ -1,10 +1,7 @@
package com.amap.flutter.map; package com.amap.flutter.map;
import android.app.Activity;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import com.amap.flutter.map.utils.LogUtil; import com.amap.flutter.map.utils.LogUtil;
@ -12,7 +9,6 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter; import io.flutter.embedding.engine.plugins.lifecycle.FlutterLifecycleAdapter;
import io.flutter.plugin.common.PluginRegistry;
/** /**
* AmapFlutterMapPlugin * AmapFlutterMapPlugin
@ -23,40 +19,17 @@ public class AMapFlutterMapPlugin implements
private static final String CLASS_NAME = "AMapFlutterMapPlugin"; private static final String CLASS_NAME = "AMapFlutterMapPlugin";
private static final String VIEW_TYPE = "com.amap.flutter.map"; private static final String VIEW_TYPE = "com.amap.flutter.map";
private Lifecycle lifecycle; private Lifecycle lifecycle;
private FlutterPluginBinding pluginBinding;
public AMapFlutterMapPlugin() { public AMapFlutterMapPlugin() {
} }
public static void registerWith(PluginRegistry.Registrar registrar) {
LogUtil.i(CLASS_NAME, "registerWith=====>");
final Activity activity = registrar.activity();
if (activity == null) {
LogUtil.w(CLASS_NAME, "activity is null!!!");
return;
}
if (activity instanceof LifecycleOwner) {
registrar
.platformViewRegistry()
.registerViewFactory(
VIEW_TYPE,
new AMapPlatformViewFactory(
registrar.messenger(),
() -> ((LifecycleOwner) activity).getLifecycle()));
} else {
registrar
.platformViewRegistry()
.registerViewFactory(
VIEW_TYPE,
new AMapPlatformViewFactory(registrar.messenger(), new ProxyLifecycleProvider(activity)));
}
}
// FlutterPlugin // FlutterPlugin
@Override @Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) { public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
LogUtil.i(CLASS_NAME, "onAttachedToEngine==>"); LogUtil.i(CLASS_NAME, "onAttachedToEngine==>");
this.pluginBinding = binding;
binding binding
.getPlatformViewRegistry() .getPlatformViewRegistry()
.registerViewFactory( .registerViewFactory(
@ -78,6 +51,13 @@ public class AMapFlutterMapPlugin implements
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
LogUtil.i(CLASS_NAME, "onAttachedToActivity==>"); LogUtil.i(CLASS_NAME, "onAttachedToActivity==>");
lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(binding); lifecycle = FlutterLifecycleAdapter.getActivityLifecycle(binding);
pluginBinding.getPlatformViewRegistry().registerViewFactory(
VIEW_TYPE,
new AMapPlatformViewFactory(
pluginBinding.getBinaryMessenger(),
() -> lifecycle
)
);
} }
@Override @Override

View File

@ -51,6 +51,8 @@ class AMapOptionsBuilder implements AMapOptionsSink, UISettingsSink {
private Object initialPolygons; private Object initialPolygons;
private String mapLanguage;
AMapPlatformView build(int id, AMapPlatformView build(int id,
Context context, Context context,
BinaryMessenger binaryMessenger, BinaryMessenger binaryMessenger,
@ -107,6 +109,8 @@ class AMapOptionsBuilder implements AMapOptionsSink, UISettingsSink {
List<Object> polygonList = (List<Object>) initialPolygons; List<Object> polygonList = (List<Object>) initialPolygons;
aMapPlatformView.getPolygonsController().addByList(polygonList); aMapPlatformView.getPolygonsController().addByList(polygonList);
} }
aMapPlatformView.getMapController().setMapLanguage(mapLanguage);
return aMapPlatformView; return aMapPlatformView;
} catch (Throwable e) { } catch (Throwable e) {
LogUtil.e(CLASS_NAME, "build", e); LogUtil.e(CLASS_NAME, "build", e);
@ -242,5 +246,9 @@ class AMapOptionsBuilder implements AMapOptionsSink, UISettingsSink {
this.initialPolygons = polygonsObject; this.initialPolygons = polygonsObject;
} }
@Override
public void setMapLanguage(String mapLanguage) {
this.mapLanguage = mapLanguage;
}
} }

View File

@ -58,4 +58,11 @@ public interface AMapOptionsSink extends UISettingsSink {
public void setInitialPolylines(Object initialPolylines); public void setInitialPolylines(Object initialPolylines);
public void setInitialPolygons(Object initialPolygons); public void setInitialPolygons(Object initialPolygons);
/**
* 设置地图语言
*
* @param mapLanguage {@link com.amap.api.maps.AMap#CHINESE }, {@link com.amap.api.maps.AMap#ENGLISH }
*/
void setMapLanguage(String mapLanguage);
} }

View File

@ -355,6 +355,13 @@ public class MapController
//不实现 //不实现
} }
@Override
public void setMapLanguage(String mapLanguage) {
if (null != amap) {
amap.setMapLanguage(mapLanguage);
}
}
@Override @Override
public void setLogoPosition(int logoPosition) { public void setLogoPosition(int logoPosition) {

View File

@ -1,14 +1,12 @@
package com.amap.flutter.map.overlays.marker; package com.amap.flutter.map.overlays.marker;
import android.graphics.Color;
import android.text.TextUtils; import android.text.TextUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import com.amap.api.maps.AMap; import com.amap.api.maps.AMap;
import com.amap.api.maps.model.LatLng; import com.amap.api.maps.model.*;
import com.amap.api.maps.model.Marker;
import com.amap.api.maps.model.MarkerOptions;
import com.amap.api.maps.model.Poi;
import com.amap.flutter.map.MyMethodCallHandler; import com.amap.flutter.map.MyMethodCallHandler;
import com.amap.flutter.map.overlays.AbstractOverlayController; import com.amap.flutter.map.overlays.AbstractOverlayController;
import com.amap.flutter.map.utils.Const; import com.amap.flutter.map.utils.Const;

View File

@ -30,7 +30,8 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import io.flutter.view.FlutterMain; import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.loader.FlutterLoader;
/** /**
* @author whm * @author whm
@ -44,6 +45,15 @@ public class ConvertUtil {
private static final int[] LocationTypeMap = new int[]{MyLocationStyle.LOCATION_TYPE_SHOW, MyLocationStyle.LOCATION_TYPE_FOLLOW, MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE}; private static final int[] LocationTypeMap = new int[]{MyLocationStyle.LOCATION_TYPE_SHOW, MyLocationStyle.LOCATION_TYPE_FOLLOW, MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE};
public static float density; public static float density;
private static String apiKey; private static String apiKey;
private static FlutterLoader flutterLoader; // For asset loading
public static void initialize(Context context) {
flutterLoader = new FlutterLoader();
if (!flutterLoader.initialized()) {
flutterLoader.startInitialization(context);
flutterLoader.ensureInitializationComplete(context, null);
}
}
public static void setPrivacyStatement(Context context, Object object) { public static void setPrivacyStatement(Context context, Object object) {
if (null == object) { if (null == object) {
@ -293,6 +303,11 @@ public class ConvertUtil {
if (null != logoLeftMargin) { if (null != logoLeftMargin) {
sink.setLogoLeftMargin(toInt(logoLeftMargin)); sink.setLogoLeftMargin(toInt(logoLeftMargin));
} }
final Object mapLanguage = data.get("mapLanguage");
if (null != mapLanguage) {
sink.setMapLanguage(toString(mapLanguage));
}
} catch (Throwable e) { } catch (Throwable e) {
LogUtil.e(CLASS_NAME, "interpretAMapOptions", e); LogUtil.e(CLASS_NAME, "interpretAMapOptions", e);
} }
@ -391,15 +406,15 @@ public class ConvertUtil {
case "fromAsset": case "fromAsset":
if (data.size() == 2) { if (data.size() == 2) {
return BitmapDescriptorFactory.fromAsset( return BitmapDescriptorFactory.fromAsset(
FlutterMain.getLookupKeyForAsset(toString(data.get(1)))); flutterLoader.getLookupKeyForAsset(toString(data.get(1))));
} else { } else {
return BitmapDescriptorFactory.fromAsset( return BitmapDescriptorFactory.fromAsset(
FlutterMain.getLookupKeyForAsset(toString(data.get(1)), toString(data.get(2)))); flutterLoader.getLookupKeyForAsset(toString(data.get(1)), toString(data.get(2))));
} }
case "fromAssetImage": case "fromAssetImage":
if (data.size() == 3) { if (data.size() == 3) {
return BitmapDescriptorFactory.fromAsset( return BitmapDescriptorFactory.fromAsset(
FlutterMain.getLookupKeyForAsset(toString(data.get(1)))); flutterLoader.getLookupKeyForAsset(toString(data.get(1))));
} else { } else {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"'fromAssetImage' Expected exactly 3 arguments, got: " + data.size()); "'fromAssetImage' Expected exactly 3 arguments, got: " + data.size());

View File

@ -26,7 +26,8 @@ if (flutterVersionName == null) {
android { android {
compileSdkVersion 34 namespace = "com.amap.flutter.amap_map_example"
compileSdkVersion 35
lint { lint {
disable 'InvalidPackage' disable 'InvalidPackage'
@ -36,7 +37,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.amap.flutter.amap_map_example" applicationId "com.amap.flutter.amap_map_example"
minSdkVersion flutter.minSdkVersion minSdkVersion flutter.minSdkVersion
targetSdkVersion 33 targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
} }
@ -69,7 +70,7 @@ android {
jniLibs.srcDirs = ['libs'] jniLibs.srcDirs = ['libs']
} }
} }
ndkVersion '25.1.8937393' ndkVersion '27.0.12077973'
} }
dependencies { dependencies {
} }

View File

@ -19,6 +19,7 @@
<application <application
android:allowNativeHeapPointerTagging="false" android:allowNativeHeapPointerTagging="false"
android:enableOnBackInvokedCallback="true"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="amap_map_example"> android:label="amap_map_example">

View File

@ -1,4 +1,15 @@
org.gradle.jvmargs=-Xmx1536M ## For more details on how to configure your build environment visit
android.useAndroidX=true # http://www.gradle.org/docs/current/userguide/build_environment.html
#
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx1024m -XX:MaxPermSize=256m
org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
# org.gradle.parallel=true
#Tue Mar 11 22:34:19 CST 2025
android.enableJetifier=true android.enableJetifier=true
#android.enableR8=true android.useAndroidX=true

View File

@ -1,6 +1,6 @@
#Fri Jun 23 08:50:38 CEST 2017 #Tue Mar 11 20:48:47 CST 2025
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip

View File

@ -18,8 +18,8 @@ pluginManagement {
plugins { plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0" id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.4.2" apply false id "com.android.application" version "8.9.0" apply false
id "org.jetbrains.kotlin.android" version "1.7.10" apply false id "org.jetbrains.kotlin.android" version "2.1.10" apply false
} }
include ":app" include ":app"

View File

@ -1,7 +1,7 @@
PODS: PODS:
- AMap3DMap (10.0.800): - AMap3DMap (10.1.200):
- AMapFoundation (>= 1.8.0) - AMapFoundation (>= 1.8.0)
- amap_map (1.0.3): - amap_map (1.0.8):
- AMap3DMap - AMap3DMap
- Flutter - Flutter
- AMapFoundation (1.8.2) - AMapFoundation (1.8.2)
@ -28,8 +28,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/permission_handler_apple/ios" :path: ".symlinks/plugins/permission_handler_apple/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
AMap3DMap: 6761e0381f517978312e4f795ce77b2b9f6781a6 AMap3DMap: 220e48934bc6553a15251c8c86f581a802787506
amap_map: 8773e5cacc760edf208b1e6e61000241d26385fa amap_map: 5be213f350872f6ea406be964031572ab9a0d6e1
AMapFoundation: 9885c48fc3a78fdfb84a0299a2293e56ea3c9fec AMapFoundation: 9885c48fc3a78fdfb84a0299a2293e56ea3c9fec
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
class AnimatedCategoryItem extends StatelessWidget { class AnimatedCategoryItem extends StatelessWidget {
AnimatedCategoryItem({ AnimatedCategoryItem({
super.key,
required double startDelayFraction, required double startDelayFraction,
required this.controller, required this.controller,
required this.child, required this.child,
@ -27,7 +28,7 @@ class AnimatedCategoryItem extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AnimatedBuilder( return AnimatedBuilder(
animation: controller, animation: controller,
builder: (context, child) { builder: (BuildContext context, Widget? child) {
return Padding( return Padding(
padding: EdgeInsets.only(top: topPaddingAnimation.value), padding: EdgeInsets.only(top: topPaddingAnimation.value),
child: child, child: child,

View File

@ -172,7 +172,6 @@ class _CategoryHeader extends StatelessWidget {
margin: margin, margin: margin,
child: Material( child: Material(
shape: RoundedRectangleBorder(borderRadius: borderRadius), shape: RoundedRectangleBorder(borderRadius: borderRadius),
color: colorScheme.onBackground,
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: SizedBox( child: SizedBox(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
@ -198,10 +197,7 @@ class _CategoryHeader extends StatelessWidget {
padding: const EdgeInsetsDirectional.only(start: 8), padding: const EdgeInsetsDirectional.only(start: 8),
child: Text( child: Text(
category.toDisplayTitle(), category.toDisplayTitle(),
style: style: Theme.of(context).textTheme.headlineMedium,
Theme.of(context).textTheme.headlineMedium!.apply(
color: colorScheme.onSurface,
),
), ),
), ),
], ],
@ -268,7 +264,6 @@ class CategoryDemoItem extends StatelessWidget {
return Material( return Material(
// Makes integration tests possible. // Makes integration tests possible.
key: ValueKey(demo.describe), key: ValueKey(demo.describe),
color: Theme.of(context).colorScheme.surface,
child: MergeSemantics( child: MergeSemantics(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
@ -292,8 +287,7 @@ class CategoryDemoItem extends StatelessWidget {
children: [ children: [
Text( Text(
demo.title, demo.title,
style: textTheme.titleMedium! style: textTheme.titleMedium,
.apply(color: colorScheme.onSurface),
), ),
Text( Text(
demo.subtitle, demo.subtitle,
@ -305,7 +299,7 @@ class CategoryDemoItem extends StatelessWidget {
Divider( Divider(
thickness: 1, thickness: 1,
height: 1, height: 1,
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
), ),
], ],
), ),

View File

@ -2,9 +2,9 @@ import 'dart:collection';
import 'package:amap_map_example/main.dart'; import 'package:amap_map_example/main.dart';
import 'package:amap_map_example/pages/interactive/map_ui_options.dart'; import 'package:amap_map_example/pages/interactive/map_ui_options.dart';
import 'package:amap_map_example/pages/map/change_map_lang.dart';
import 'package:amap_map_example/pages/map/limit_map_bounds.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/map_my_location.dart';
import 'package:amap_map_example/pages/map/map_with_extension_page.dart';
import 'package:amap_map_example/pages/map/show_map_page.dart'; import 'package:amap_map_example/pages/map/show_map_page.dart';
import 'package:amap_map_example/pages/overlays/custom_info_window.dart'; import 'package:amap_map_example/pages/overlays/custom_info_window.dart';
import 'package:amap_map_example/pages/overlays/marker_config.dart'; import 'package:amap_map_example/pages/overlays/marker_config.dart';
@ -18,8 +18,7 @@ class DemoConfiguration {
final WidgetBuilder buildRoute; final WidgetBuilder buildRoute;
} }
List<Demo> allDemos() => List<Demo> allDemos() => mapDemos() + interactiveDemos() + overlayDemos();
mapDemos() + interactiveDemos() + overlayDemos() + extensionDemos();
List<Demo> mapDemos() { List<Demo> mapDemos() {
return [ return [
@ -47,6 +46,14 @@ List<Demo> mapDemos() {
configurations: [ configurations: [
DemoConfiguration(buildRoute: (context) => LimitMapBoundsPage()) DemoConfiguration(buildRoute: (context) => LimitMapBoundsPage())
]), ]),
Demo(
title: '地图显示语言',
category: DemoCategory.basic,
subtitle: '演示限定手机屏幕显示地图的范围',
slug: 'map-lang',
configurations: [
DemoConfiguration(buildRoute: (context) => ChangeMapLangPage())
]),
]; ];
} }
@ -84,19 +91,6 @@ List<Demo> overlayDemos() {
]; ];
} }
List<Demo> extensionDemos() {
return [
Demo(
title: '辅助信息获取',
category: DemoCategory.extension,
subtitle: '获取审图号',
slug: 'extension-info',
configurations: [
DemoConfiguration(buildRoute: (context) => MapWithExtensionPage())
])
];
}
Map<String?, Demo> slugToDemo(BuildContext context) { Map<String?, Demo> slugToDemo(BuildContext context) {
return LinkedHashMap<String?, Demo>.fromIterable( return LinkedHashMap<String?, Demo>.fromIterable(
allDemos(), allDemos(),

View File

@ -4,10 +4,55 @@ import 'package:amap_map_example/category_list_item.dart';
import 'package:amap_map_example/const_config.dart'; import 'package:amap_map_example/const_config.dart';
import 'package:amap_map_example/data/demos.dart'; import 'package:amap_map_example/data/demos.dart';
import 'package:amap_map_example/routes.dart'; import 'package:amap_map_example/routes.dart';
import 'package:amap_map_example/theme.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(MaterialApp(
themeMode: ThemeMode.light,
onGenerateRoute: RouteConfig.onGenerateRoute,
home: AMapDemo()));
}
enum DemoCategory {
basic,
interactive,
overlay,
extension;
String toDisplayTitle() {
switch (this) {
case basic:
return '创建地图';
case interactive:
return '与地图交互';
case overlay:
return '在地图上绘制';
case extension:
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}';
}
final List<Permission> needPermissionList = [ final List<Permission> needPermissionList = [
Permission.location, Permission.location,
Permission.storage, Permission.storage,
@ -79,13 +124,6 @@ class _AMapDemoState extends State<AMapDemo>
category: DemoCategory.overlay, category: DemoCategory.overlay,
demos: overlayDemos(), demos: overlayDemos(),
)), )),
AnimatedCategoryItem(
startDelayFraction: 0.15,
controller: _animationController,
child: CategoryListItem(
category: DemoCategory.extension,
demos: extensionDemos(),
)),
], ],
), ),
); );
@ -100,49 +138,4 @@ class _AMapDemoState extends State<AMapDemo>
} }
} }
void main() {
runApp(MaterialApp(
theme: ThemeData(colorScheme: DemoThemeData.lightColorScheme),
themeMode: ThemeMode.light,
onGenerateRoute: RouteConfig.onGenerateRoute,
home: AMapDemo()));
}
enum DemoCategory {
basic,
interactive,
overlay,
extension;
String toDisplayTitle() {
switch (this) {
case basic:
return '创建地图';
case interactive:
return '与地图交互';
case overlay:
return '在地图上绘制';
case extension:
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

@ -4,10 +4,10 @@ import 'package:amap_map_example/widgets/amap_switch_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class GesturesDemoPage extends StatefulWidget { class GesturesDemoPage extends StatefulWidget {
GesturesDemoPage({Key? key}) : super(key: key); GesturesDemoPage({super.key});
@override @override
_BodyState createState() => _BodyState(); State<GesturesDemoPage> createState() => _BodyState();
} }
class _BodyState extends State<GesturesDemoPage> { class _BodyState extends State<GesturesDemoPage> {
@ -71,7 +71,7 @@ class _BodyState extends State<GesturesDemoPage> {
}, },
), ),
]; ];
Widget _gesturesOptiosWeidget() { Widget gesturesOptiosWeidget() {
return Container( return Container(
padding: EdgeInsets.all(5), padding: EdgeInsets.all(5),
child: Column( child: Column(
@ -103,7 +103,7 @@ class _BodyState extends State<GesturesDemoPage> {
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Container( child: Container(
child: _gesturesOptiosWeidget(), child: gesturesOptiosWeidget(),
), ),
), ),
), ),

View File

@ -4,13 +4,12 @@ import 'package:amap_map_example/widgets/amap_radio_group.dart';
import 'package:amap_map_example/widgets/amap_switch_button.dart'; import 'package:amap_map_example/widgets/amap_switch_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:x_amap_base/x_amap_base.dart'; import 'package:x_amap_base/x_amap_base.dart';
import 'package:x_common/utils/logger.dart';
class MapUIDemoPage extends StatefulWidget { class MapUIDemoPage extends StatefulWidget {
MapUIDemoPage({Key? key}) : super(key: key); MapUIDemoPage({super.key});
@override @override
_BodyState createState() => _BodyState(); State<MapUIDemoPage> createState() => _BodyState();
} }
class _BodyState extends State<MapUIDemoPage> { class _BodyState extends State<MapUIDemoPage> {
@ -53,7 +52,7 @@ class _BodyState extends State<MapUIDemoPage> {
); );
//ui控制 //ui控制
final List<Widget> _uiOptions = [ final List<Widget> uiOptions = [
AMapSwitchButton( AMapSwitchButton(
label: Text('显示路况'), label: Text('显示路况'),
defaultValue: _trafficEnabled, defaultValue: _trafficEnabled,
@ -101,7 +100,7 @@ class _BodyState extends State<MapUIDemoPage> {
), ),
]; ];
Widget _uiOptionsWidget() { Widget uiOptionsWidget() {
return Container( return Container(
padding: EdgeInsets.all(5), padding: EdgeInsets.all(5),
child: Column( child: Column(
@ -111,7 +110,7 @@ class _BodyState extends State<MapUIDemoPage> {
Text('UI操作', style: TextStyle(fontWeight: FontWeight.w600)), Text('UI操作', style: TextStyle(fontWeight: FontWeight.w600)),
Container( Container(
padding: EdgeInsets.only(left: 10), padding: EdgeInsets.only(left: 10),
child: AMapGradView(childrenWidgets: _uiOptions), child: AMapGradView(childrenWidgets: uiOptions),
), ),
AMapRadioGroup<LogoPosition?>( AMapRadioGroup<LogoPosition?>(
groupLabel: 'Logo位置', groupLabel: 'Logo位置',
@ -170,7 +169,7 @@ class _BodyState extends State<MapUIDemoPage> {
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Container( child: Container(
child: _uiOptionsWidget(), child: uiOptionsWidget(),
), ),
), ),
), ),

View File

@ -4,10 +4,10 @@ import 'package:amap_map_example/widgets/amap_gridview.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class MoveCameraDemoPage extends StatefulWidget { class MoveCameraDemoPage extends StatefulWidget {
MoveCameraDemoPage({Key? key}) : super(key: key); const MoveCameraDemoPage({super.key});
@override @override
_BodyState createState() => _BodyState(); State<MoveCameraDemoPage> createState() => _BodyState();
} }
class _BodyState extends State<MoveCameraDemoPage> { class _BodyState extends State<MoveCameraDemoPage> {
@ -20,23 +20,23 @@ class _BodyState extends State<MoveCameraDemoPage> {
onCameraMove: _onCameraMove, onCameraMove: _onCameraMove,
onCameraMoveEnd: _onCameraMoveEnd, onCameraMoveEnd: _onCameraMoveEnd,
); );
List<Widget> _optionsWidget = [ List<Widget> optionsWidget = [
_createMyFloatButton('改变显示区域', _changeLatLngBounds), _createMyFloatButton('改变显示区域', _changeLatLngBounds),
_createMyFloatButton('改变中心点', _changeCameraPosition), _createMyFloatButton('改变中心点', _changeCameraPosition),
_createMyFloatButton('改变缩放级别到18', _changeCameraZoom), _createMyFloatButton('改变缩放级别到18', _changeCameraZoom),
_createMyFloatButton('按照像素移动地图', _scrollBy), _createMyFloatButton('按照像素移动地图', _scrollBy),
]; ];
Widget _cameraOptions() { Widget cameraOptions() {
return Container( return Container(
padding: EdgeInsets.all(5), padding: const EdgeInsets.all(5),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Container( Container(
child: AMapGradView( child: AMapGradView(
childrenWidgets: _optionsWidget, childrenWidgets: optionsWidget,
), ),
), ),
], ],
@ -45,7 +45,7 @@ class _BodyState extends State<MoveCameraDemoPage> {
} }
return ConstrainedBox( return ConstrainedBox(
constraints: BoxConstraints.expand(), constraints: const BoxConstraints.expand(),
child: Column( child: Column(
children: [ children: [
ConstrainedBox( ConstrainedBox(
@ -54,7 +54,7 @@ class _BodyState extends State<MoveCameraDemoPage> {
minHeight: MediaQuery.of(context).size.height * 0.7), minHeight: MediaQuery.of(context).size.height * 0.7),
child: Stack( child: Stack(
children: [ children: [
Container( SizedBox(
height: MediaQuery.of(context).size.height * 0.7, height: MediaQuery.of(context).size.height * 0.7,
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
child: amap, child: amap,
@ -66,28 +66,28 @@ class _BodyState extends State<MoveCameraDemoPage> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
InkResponse( InkResponse(
onTap: _zoomIn,
child: Container( child: Container(
child: Icon( width: 40,
height: 40,
color: Colors.blue,
child: const Icon(
Icons.add, Icons.add,
color: Colors.white, color: Colors.white,
), ),
width: 40,
height: 40,
color: Colors.blue,
), ),
onTap: _zoomIn,
), ),
InkResponse( InkResponse(
onTap: _zoomOut,
child: Container( child: Container(
child: Icon( color: Colors.blue,
width: 40,
height: 40,
child: const Icon(
Icons.remove, Icons.remove,
color: Colors.white, color: Colors.white,
), ),
color: Colors.blue,
width: 40,
height: 40,
), ),
onTap: _zoomOut,
), ),
], ],
), ),
@ -103,16 +103,16 @@ class _BodyState extends State<MoveCameraDemoPage> {
? Container( ? Container(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
color: Colors.grey, color: Colors.grey,
padding: EdgeInsets.all(5), padding: const EdgeInsets.all(5),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
_currentZoom!, _currentZoom!,
style: TextStyle(color: Colors.white), style: const TextStyle(color: Colors.white),
), ),
) )
: SizedBox(), : const SizedBox(),
Container( Container(
child: _cameraOptions(), child: cameraOptions(),
), ),
], ],
), ),
@ -141,7 +141,7 @@ class _BodyState extends State<MoveCameraDemoPage> {
void _changeCameraPosition() { void _changeCameraPosition() {
_mapController?.moveCamera( _mapController?.moveCamera(
CameraUpdate.newCameraPosition( CameraUpdate.newCameraPosition(
CameraPosition( const CameraPosition(
//中心点 //中心点
target: LatLng(31.230378, 121.473658), target: LatLng(31.230378, 121.473658),
//缩放级别 //缩放级别
@ -184,8 +184,8 @@ class _BodyState extends State<MoveCameraDemoPage> {
_mapController?.moveCamera( _mapController?.moveCamera(
CameraUpdate.newLatLngBounds( CameraUpdate.newLatLngBounds(
LatLngBounds( LatLngBounds(
southwest: LatLng(33.789925, 104.838326), southwest: const LatLng(33.789925, 104.838326),
northeast: LatLng(38.740688, 114.647472)), northeast: const LatLng(38.740688, 114.647472)),
15.0), 15.0),
animated: true, animated: true,
); );
@ -204,16 +204,16 @@ class _BodyState extends State<MoveCameraDemoPage> {
return TextButton( return TextButton(
onPressed: onPressed, onPressed: onPressed,
style: ButtonStyle( style: ButtonStyle(
shape: MaterialStateProperty.all( shape: WidgetStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))), RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
//文字颜色 //文字颜色
foregroundColor: MaterialStateProperty.all(Colors.white), foregroundColor: WidgetStateProperty.all(Colors.white),
//水波纹颜色 //水波纹颜色
overlayColor: MaterialStateProperty.all(Colors.blueAccent), overlayColor: WidgetStateProperty.all(Colors.blueAccent),
//背景颜色 //背景颜色
backgroundColor: MaterialStateProperty.resolveWith((states) { backgroundColor: WidgetStateProperty.resolveWith((states) {
//设置按下时的背景颜色 //设置按下时的背景颜色
if (states.contains(MaterialState.pressed)) { if (states.contains(WidgetState.pressed)) {
return Colors.blueAccent; return Colors.blueAccent;
} }
//默认背景颜色 //默认背景颜色

View File

@ -3,10 +3,10 @@ import 'package:x_amap_base/x_amap_base.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class PoiClickDemoPage extends StatefulWidget { class PoiClickDemoPage extends StatefulWidget {
PoiClickDemoPage({Key? key}) : super(key: key); PoiClickDemoPage({super.key});
@override @override
_BodyState createState() => _BodyState(); State<PoiClickDemoPage> createState() => _BodyState();
} }
class _BodyState extends State<PoiClickDemoPage> { class _BodyState extends State<PoiClickDemoPage> {

View File

@ -32,16 +32,16 @@ class _SnapShotState extends State<SnapshotPage> {
child: TextButton( child: TextButton(
child: Text('截屏'), child: Text('截屏'),
style: ButtonStyle( style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder( shape: WidgetStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10))), borderRadius: BorderRadius.circular(10))),
//文字颜色 //文字颜色
foregroundColor: MaterialStateProperty.all(Colors.white), foregroundColor: WidgetStateProperty.all(Colors.white),
//水波纹颜色 //水波纹颜色
overlayColor: MaterialStateProperty.all(Colors.blueAccent), overlayColor: WidgetStateProperty.all(Colors.blueAccent),
//背景颜色 //背景颜色
backgroundColor: MaterialStateProperty.resolveWith((states) { backgroundColor: WidgetStateProperty.resolveWith((states) {
//设置按下时的背景颜色 //设置按下时的背景颜色
if (states.contains(MaterialState.pressed)) { if (states.contains(WidgetState.pressed)) {
return Colors.blueAccent; return Colors.blueAccent;
} }
//默认背景颜色 //默认背景颜色

View File

@ -0,0 +1,73 @@
// Copyright 2024 kuloud
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
import 'package:amap_map/amap_map.dart';
import 'package:amap_map_example/widgets/amap_radio_group.dart';
import 'package:flutter/material.dart';
class ChangeMapLangPage extends StatefulWidget {
ChangeMapLangPage({super.key});
@override
State<ChangeMapLangPage> createState() => _PageBodyState();
}
class _PageBodyState extends State<ChangeMapLangPage> {
MapLanguage? _mapLang;
final Map<String, MapLanguage> _radioValueMap = {
'中文': MapLanguage.chinese,
'English': MapLanguage.english,
};
@override
void initState() {
super.initState();
_mapLang = MapLanguage.chinese;
}
@override
Widget build(BuildContext context) {
//创建地图
final AMapWidget map = AMapWidget(
mapLanguage: _mapLang,
);
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: _mapLang,
radioValueMap: _radioValueMap,
onChanged: (value) => {
setState(() {
_mapLang = value;
})
},
),
),
),
),
],
),
);
}
}

View File

@ -3,10 +3,10 @@ import 'package:amap_map_example/widgets/amap_radio_group.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ChangeMapTypePage extends StatefulWidget { class ChangeMapTypePage extends StatefulWidget {
ChangeMapTypePage({Key? key}) : super(key: key); ChangeMapTypePage({super.key});
@override @override
_PageBodyState createState() => _PageBodyState(); State<ChangeMapTypePage> createState() => _PageBodyState();
} }
class _PageBodyState extends State<ChangeMapTypePage> { class _PageBodyState extends State<ChangeMapTypePage> {

View File

@ -4,16 +4,16 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
class CustomMapStylePage extends StatefulWidget { class CustomMapStylePage extends StatefulWidget {
CustomMapStylePage({Key? key}) : super(key: key); CustomMapStylePage({super.key});
@override @override
_CustomMapStyleState createState() => _CustomMapStyleState(); State<CustomMapStylePage> createState() => _CustomMapStyleState();
} }
class _CustomMapStyleState extends State<CustomMapStylePage> { class _CustomMapStyleState extends State<CustomMapStylePage> {
bool _mapCreated = false; bool _mapCreated = false;
CustomStyleOptions _customStyleOptions = CustomStyleOptions(false); final CustomStyleOptions _customStyleOptions = CustomStyleOptions(false);
//加载自定义地图样式 //加载自定义地图样式
void _loadCustomData() async { void _loadCustomData() async {
ByteData styleByteData = await rootBundle.load('assets/style.data'); ByteData styleByteData = await rootBundle.load('assets/style.data');

View File

@ -3,10 +3,10 @@ import 'package:x_amap_base/x_amap_base.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class LimitMapBoundsPage extends StatefulWidget { class LimitMapBoundsPage extends StatefulWidget {
LimitMapBoundsPage({Key? key}) : super(key: key); LimitMapBoundsPage({super.key});
@override @override
_BodyState createState() => _BodyState(); State<LimitMapBoundsPage> createState() => _BodyState();
} }
class _BodyState extends State<LimitMapBoundsPage> { class _BodyState extends State<LimitMapBoundsPage> {

View File

@ -1,5 +1,3 @@
import 'dart:typed_data';
import 'package:amap_map/amap_map.dart'; import 'package:amap_map/amap_map.dart';
import 'package:amap_map_example/widgets/amap_switch_button.dart'; import 'package:amap_map_example/widgets/amap_switch_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -8,13 +6,15 @@ import 'package:flutter/services.dart';
import 'package:x_amap_base/x_amap_base.dart'; import 'package:x_amap_base/x_amap_base.dart';
class AllMapConfigDemoPage extends StatefulWidget { class AllMapConfigDemoPage extends StatefulWidget {
const AllMapConfigDemoPage({super.key});
@override @override
State<StatefulWidget> createState() => _MapUiBodyState(); State<StatefulWidget> createState() => _MapUiBodyState();
} }
class _MapUiBodyState extends State<AllMapConfigDemoPage> { class _MapUiBodyState extends State<AllMapConfigDemoPage> {
//默认显示在北京天安门 //默认显示在北京天安门
static final CameraPosition _kInitialPosition = const CameraPosition( static const CameraPosition _kInitialPosition = CameraPosition(
target: LatLng(39.909187, 116.397451), target: LatLng(39.909187, 116.397451),
zoom: 10.0, zoom: 10.0,
); );
@ -54,10 +54,10 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
late AMapController _controller; late AMapController _controller;
CustomStyleOptions _customStyleOptions = CustomStyleOptions(false); final CustomStyleOptions _customStyleOptions = CustomStyleOptions(false);
///自定义定位小蓝点 ///自定义定位小蓝点
MyLocationStyleOptions _myLocationStyleOptions = final MyLocationStyleOptions _myLocationStyleOptions =
MyLocationStyleOptions(false); MyLocationStyleOptions(false);
@override @override
void initState() { void initState() {
@ -100,7 +100,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
onPoiTouched: _onMapPoiTouched, onPoiTouched: _onMapPoiTouched,
); );
Widget _mapTypeRadio(String label, MapType radioValue) { Widget mapTypeRadio(String label, MapType radioValue) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@ -118,18 +118,18 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
); );
} }
final List<Widget> _mapTypeList = [ final List<Widget> mapTypeList = [
_mapTypeRadio('普通地图', MapType.normal), mapTypeRadio('普通地图', MapType.normal),
_mapTypeRadio('卫星地图', MapType.satellite), mapTypeRadio('卫星地图', MapType.satellite),
_mapTypeRadio('导航地图', MapType.navi), mapTypeRadio('导航地图', MapType.navi),
_mapTypeRadio('公交地图', MapType.bus), mapTypeRadio('公交地图', MapType.bus),
_mapTypeRadio('黑夜模式', MapType.night), mapTypeRadio('黑夜模式', MapType.night),
]; ];
//ui控制 //ui控制
final List<Widget> _uiOptions = [ final List<Widget> uiOptions = [
AMapSwitchButton( AMapSwitchButton(
label: Text('显示路况'), label: const Text('显示路况'),
defaultValue: _trafficEnabled, defaultValue: _trafficEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -138,7 +138,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
}, },
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('显示3D建筑物'), label: const Text('显示3D建筑物'),
defaultValue: _buildingsEnabled, defaultValue: _buildingsEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -147,7 +147,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
}, },
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('显示指南针'), label: const Text('显示指南针'),
defaultValue: _compassEnabled, defaultValue: _compassEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -156,7 +156,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
}, },
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('显示地图文字'), label: const Text('显示地图文字'),
defaultValue: _labelsEnabled, defaultValue: _labelsEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -165,7 +165,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
}, },
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('显示比例尺'), label: const Text('显示比例尺'),
defaultValue: _scaleEnabled, defaultValue: _scaleEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -174,7 +174,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
}, },
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('点击Poi'), label: const Text('点击Poi'),
defaultValue: _touchPoiEnabled, defaultValue: _touchPoiEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -183,7 +183,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
}, },
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('自定义地图'), label: const Text('自定义地图'),
defaultValue: _customStyleOptions.enabled, defaultValue: _customStyleOptions.enabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -196,7 +196,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
//手势开关 //手势开关
final List<Widget> gesturesOptions = [ final List<Widget> gesturesOptions = [
AMapSwitchButton( AMapSwitchButton(
label: Text('旋转'), label: const Text('旋转'),
defaultValue: _rotateGesturesEnabled, defaultValue: _rotateGesturesEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -205,7 +205,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
}, },
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('滑动'), label: const Text('滑动'),
defaultValue: _scrollGesturesEnabled, defaultValue: _scrollGesturesEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -214,7 +214,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
}, },
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('倾斜'), label: const Text('倾斜'),
defaultValue: _tiltGesturesEnabled, defaultValue: _tiltGesturesEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -223,7 +223,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
}, },
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('缩放'), label: const Text('缩放'),
defaultValue: _zoomGesturesEnabled, defaultValue: _zoomGesturesEnabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -233,34 +233,34 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
), ),
]; ];
Widget _mapTypeOptions() { Widget mapTypeOptions() {
return Container( return Container(
padding: EdgeInsets.all(5), padding: const EdgeInsets.all(5),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text('地图样式', style: TextStyle(fontWeight: FontWeight.w600)), const Text('地图样式', style: TextStyle(fontWeight: FontWeight.w600)),
Container( Container(
padding: EdgeInsets.only(left: 10), padding: const EdgeInsets.only(left: 10),
child: createGridView(_mapTypeList), child: createGridView(mapTypeList),
), ),
], ],
), ),
); );
} }
Widget _myLocationStyleContainer() { Widget myLocationStyleContainer() {
return Container( return Container(
padding: EdgeInsets.all(5), padding: const EdgeInsets.all(5),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
// Text('定位小蓝点', style: TextStyle(fontWeight: FontWeight.w600)), // Text('定位小蓝点', style: TextStyle(fontWeight: FontWeight.w600)),
AMapSwitchButton( AMapSwitchButton(
label: label: const Text('定位小蓝点',
Text('定位小蓝点', style: TextStyle(fontWeight: FontWeight.w600)), style: TextStyle(fontWeight: FontWeight.w600)),
defaultValue: _myLocationStyleOptions.enabled, defaultValue: _myLocationStyleOptions.enabled,
onSwitchChanged: (value) => { onSwitchChanged: (value) => {
setState(() { setState(() {
@ -273,33 +273,33 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
); );
} }
Widget _uiOptionsWidget() { Widget uiOptionsWidget() {
return Container( return Container(
padding: EdgeInsets.all(5), padding: const EdgeInsets.all(5),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text('UI操作', style: TextStyle(fontWeight: FontWeight.w600)), const Text('UI操作', style: TextStyle(fontWeight: FontWeight.w600)),
Container( Container(
padding: EdgeInsets.only(left: 10), padding: const EdgeInsets.only(left: 10),
child: createGridView(_uiOptions), child: createGridView(uiOptions),
), ),
], ],
), ),
); );
} }
Widget _gesturesOptiosWeidget() { Widget gesturesOptiosWeidget() {
return Container( return Container(
padding: EdgeInsets.all(5), padding: const EdgeInsets.all(5),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Text('手势控制', style: TextStyle(fontWeight: FontWeight.w600)), const Text('手势控制', style: TextStyle(fontWeight: FontWeight.w600)),
Container( Container(
padding: EdgeInsets.only(left: 10), padding: const EdgeInsets.only(left: 10),
child: createGridView(gesturesOptions), child: createGridView(gesturesOptions),
), ),
], ],
@ -307,13 +307,13 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
); );
} }
Widget _optionsItem() { Widget optionsItem() {
return Column( return Column(
children: [ children: [
_mapTypeOptions(), mapTypeOptions(),
_myLocationStyleContainer(), myLocationStyleContainer(),
_uiOptionsWidget(), uiOptionsWidget(),
_gesturesOptiosWeidget(), gesturesOptiosWeidget(),
TextButton( TextButton(
child: const Text('moveCamera到首开'), child: const Text('moveCamera到首开'),
onPressed: _moveCameraToShoukai, onPressed: _moveCameraToShoukai,
@ -337,7 +337,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Container( child: Container(
child: _optionsItem(), child: optionsItem(),
), ),
), ),
), ),
@ -366,7 +366,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
Widget createGridView(List<Widget> widgets) { Widget createGridView(List<Widget> widgets) {
return GridView.count( return GridView.count(
primary: false, primary: false,
physics: new NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
//水平子Widget之间间距 //水平子Widget之间间距
crossAxisSpacing: 1.0, crossAxisSpacing: 1.0,
//垂直子Widget之间间距 //垂直子Widget之间间距
@ -381,7 +381,7 @@ class _MapUiBodyState extends State<AllMapConfigDemoPage> {
//移动地图中心点到首开广场 //移动地图中心点到首开广场
void _moveCameraToShoukai() { void _moveCameraToShoukai() {
_controller.moveCamera(CameraUpdate.newCameraPosition(CameraPosition( _controller.moveCamera(CameraUpdate.newCameraPosition(const CameraPosition(
target: LatLng(39.993306, 116.473004), target: LatLng(39.993306, 116.473004),
zoom: 18, zoom: 18,
tilt: 30, tilt: 30,

View File

@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart'; import 'package:permission_handler/permission_handler.dart';
class MyLocationPage extends StatefulWidget { class MyLocationPage extends StatefulWidget {
MyLocationPage({Key? key}) : super(key: key); MyLocationPage({super.key});
@override @override
_BodyState createState() => _BodyState(); State<MyLocationPage> createState() => _BodyState();
} }
class _BodyState extends State<MyLocationPage> { class _BodyState extends State<MyLocationPage> {

View File

@ -1,83 +0,0 @@
// Copyright 2023-2024 kuloud
// Copyright 2020 lbs.amap.com
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// import 'package:amap_map_extensions/amap_map_extensions.dart';
import 'package:flutter/material.dart';
import 'dart:typed_data';
import 'package:amap_map/amap_map.dart';
class MapWithExtensionPage extends StatefulWidget {
@override
State<StatefulWidget> createState() => _MapWithExtensionPageState();
}
class _MapWithExtensionPageState extends State<MapWithExtensionPage> {
List<Widget> _approvalNumberWidget = <Widget>[];
// final _extension = AmapMapExtensions();
@override
Widget build(BuildContext context) {
final AMapWidget map = AMapWidget(
onMapCreated: onMapCreated,
// extensions: [_extension],
);
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 _extension.getMapContentApprovalNumber())!;
// //卫星地图审图号
// String satelliteImageApprovalNumber =
// (await _extension.getSatelliteImageApprovalNumber())!;
// setState(() {
// _approvalNumberWidget.add(Text(mapContentApprovalNumber));
// _approvalNumberWidget.add(Text(satelliteImageApprovalNumber));
// });
// print('地图审图号(普通地图): $mapContentApprovalNumber');
// print('地图审图号(卫星地图): $satelliteImageApprovalNumber');
}
}

View File

@ -2,10 +2,10 @@ import 'package:amap_map/amap_map.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class MinMaxZoomDemoPage extends StatefulWidget { class MinMaxZoomDemoPage extends StatefulWidget {
MinMaxZoomDemoPage({Key? key}) : super(key: key); const MinMaxZoomDemoPage({super.key});
@override @override
_BodyState createState() => _BodyState(); State<MinMaxZoomDemoPage> createState() => _BodyState();
} }
class _BodyState extends State<MinMaxZoomDemoPage> { class _BodyState extends State<MinMaxZoomDemoPage> {
@ -22,7 +22,7 @@ class _BodyState extends State<MinMaxZoomDemoPage> {
minMaxZoomPreference: MinMaxZoomPreference(_minZoom, _maxZoom), minMaxZoomPreference: MinMaxZoomPreference(_minZoom, _maxZoom),
); );
return ConstrainedBox( return ConstrainedBox(
constraints: BoxConstraints.expand(), constraints: const BoxConstraints.expand(),
child: Stack( child: Stack(
children: [ children: [
Container( Container(
@ -40,24 +40,24 @@ class _BodyState extends State<MinMaxZoomDemoPage> {
Container( Container(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
color: Colors.grey, color: Colors.grey,
padding: EdgeInsets.all(5), padding: const EdgeInsets.all(5),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
'当前限制的最小最大缩放级别是:[$_minZoom, $_maxZoom]', '当前限制的最小最大缩放级别是:[$_minZoom, $_maxZoom]',
style: TextStyle(color: Colors.blue), style: const TextStyle(color: Colors.blue),
), ),
), ),
_currentZoom != null _currentZoom != null
? Container( ? Container(
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
color: Colors.grey, color: Colors.grey,
padding: EdgeInsets.all(5), padding: const EdgeInsets.all(5),
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
_currentZoom!, _currentZoom!,
style: TextStyle(color: Colors.white), style: const TextStyle(color: Colors.white),
)) ))
: SizedBox(), : const SizedBox(),
], ],
), ),
), ),
@ -69,7 +69,7 @@ class _BodyState extends State<MinMaxZoomDemoPage> {
children: [ children: [
InkResponse( InkResponse(
child: Container( child: Container(
child: Icon( child: const Icon(
Icons.add, Icons.add,
color: Colors.white, color: Colors.white,
), ),
@ -81,7 +81,7 @@ class _BodyState extends State<MinMaxZoomDemoPage> {
), ),
InkResponse( InkResponse(
child: Container( child: Container(
child: Icon( child: const Icon(
Icons.remove, Icons.remove,
color: Colors.white, color: Colors.white,
), ),

View File

@ -3,7 +3,7 @@ import 'package:x_amap_base/x_amap_base.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class MultiMapDemoPage extends StatefulWidget { class MultiMapDemoPage extends StatefulWidget {
const MultiMapDemoPage(); const MultiMapDemoPage({super.key});
@override @override
State<StatefulWidget> createState() => _MultiMapDemoState(); State<StatefulWidget> createState() => _MultiMapDemoState();
} }
@ -14,7 +14,7 @@ class _MultiMapDemoState extends State<MultiMapDemoPage> {
return Container( return Container(
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
child: Column( child: const Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[ children: <Widget>[

View File

@ -8,7 +8,7 @@ class ShowMapPage extends StatefulWidget {
} }
class _ShowMapPageState extends State<ShowMapPage> { class _ShowMapPageState extends State<ShowMapPage> {
List<Widget> _approvalNumberWidget = <Widget>[]; final List<Widget> _approvalNumberWidget = <Widget>[];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final AMapWidget map = AMapWidget( final AMapWidget map = AMapWidget(
@ -43,23 +43,23 @@ class _ShowMapPageState extends State<ShowMapPage> {
void onMapCreated(AMapController controller) { void onMapCreated(AMapController controller) {
setState(() { setState(() {
_mapController = controller; _mapController = controller;
// getApprovalNumber(); getApprovalNumber();
}); });
} }
/// 获取审图号 /// 获取审图号
void getApprovalNumber() async { void getApprovalNumber() async {
// //普通地图审图号 //普通地图审图号
// String mapContentApprovalNumber = String mapContentApprovalNumber =
// (await _mapController.getMapContentApprovalNumber())!; (await _mapController.getMapContentApprovalNumber());
// //卫星地图审图号 //卫星地图审图号
// String satelliteImageApprovalNumber = String satelliteImageApprovalNumber =
// (await _mapController.getSatelliteImageApprovalNumber())!; (await _mapController.getSatelliteImageApprovalNumber());
// setState(() { setState(() {
// _approvalNumberWidget.add(Text(mapContentApprovalNumber)); _approvalNumberWidget.add(Text(mapContentApprovalNumber));
// _approvalNumberWidget.add(Text(satelliteImageApprovalNumber)); _approvalNumberWidget.add(Text(satelliteImageApprovalNumber));
// }); });
// print('地图审图号(普通地图): $mapContentApprovalNumber'); print('地图审图号(普通地图): $mapContentApprovalNumber');
// print('地图审图号(卫星地图): $satelliteImageApprovalNumber'); print('地图审图号(卫星地图): $satelliteImageApprovalNumber');
} }
} }

View File

@ -18,20 +18,17 @@ class CustomInfoWindowDemoPage extends StatefulWidget {
class _State extends State<CustomInfoWindowDemoPage> { class _State extends State<CustomInfoWindowDemoPage> {
static final LatLng mapCenter = const LatLng(39.909187, 116.397451); static final LatLng mapCenter = const LatLng(39.909187, 116.397451);
Map<String, Marker> _markers = <String, Marker>{}; final Map<String, Marker> _markers = <String, Marker>{};
BitmapDescriptor? _markerIcon; BitmapDescriptor? _markerIcon;
String? selectedMarkerId; String? selectedMarkerId;
bool showInfoWindow = false; bool showInfoWindow = false;
AMapController? _controller;
final _infoWindowExtension = InfoWindowExtension( Future<void> _onMapCreated(AMapController controller) async {
infoWindow: Container( setState(() {
color: Colors.lightBlue.shade400, _controller = controller;
child: Text('info'), });
), }
option: InfoWindowOption(
latLng: mapCenter, offset: EdgeInsets.only(bottom: 32)));
Future<void> _onMapCreated(AMapController controller) async {}
void _add() { void _add() {
final int markerCount = _markers.length; final int markerCount = _markers.length;
@ -42,8 +39,8 @@ class _State extends State<CustomInfoWindowDemoPage> {
position: markPostion, position: markPostion,
icon: _markerIcon!, icon: _markerIcon!,
infoWindow: InfoWindow(title: '$markerCount 个Marker'), infoWindow: InfoWindow(title: '$markerCount 个Marker'),
onTap: (markerId) => _onMarkerTapped(markerId), onTap: (String markerId) => _onMarkerTapped(markerId),
onDragEnd: (markerId, endPosition) => onDragEnd: (String markerId, LatLng endPosition) =>
_onMarkerDragEnd(markerId, endPosition), _onMarkerDragEnd(markerId, endPosition),
); );
@ -80,7 +77,7 @@ class _State extends State<CustomInfoWindowDemoPage> {
} }
void _removeAll() { void _removeAll() {
if (_markers.length > 0) { if (_markers.isNotEmpty) {
setState(() { setState(() {
_markers.clear(); _markers.clear();
selectedMarkerId = null.toString(); selectedMarkerId = null.toString();
@ -90,7 +87,7 @@ class _State extends State<CustomInfoWindowDemoPage> {
void _changeInfo() async { void _changeInfo() async {
final Marker marker = _markers[selectedMarkerId]!; final Marker marker = _markers[selectedMarkerId]!;
final String newTitle = marker.infoWindow.title! + '*'; final String newTitle = '${marker.infoWindow.title!}*';
if (selectedMarkerId != null) { if (selectedMarkerId != null) {
setState(() { setState(() {
_markers[selectedMarkerId!] = marker.copyWith( _markers[selectedMarkerId!] = marker.copyWith(
@ -168,7 +165,7 @@ class _State extends State<CustomInfoWindowDemoPage> {
setState(() { setState(() {
showInfoWindow = value; showInfoWindow = value;
_markers[selectedMarkerId!] = marker.copyWith( _markers[selectedMarkerId!] = marker.copyWith(
// visibleParam: value, visibleParam: value,
); );
}); });
} }
@ -186,18 +183,12 @@ class _State extends State<CustomInfoWindowDemoPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
///以下几种获取自定图片的方式使用其中一种即可。 ///以下几种获取自定图片的方式使用其中一种即可。
//最简单的方式 //最简单的方式
if (null == _markerIcon) { _markerIcon ??= BitmapDescriptor.fromIconPath('assets/location_marker.png');
_markerIcon = BitmapDescriptor.fromIconPath('assets/location_marker.png');
}
_infoWindowExtension.option?.show = AMapWidget map = AMapWidget(
_markers[selectedMarkerId] != null && showInfoWindow;
_infoWindowExtension.option?.latLng = _markers[selectedMarkerId]?.position;
final AMapWidget map = AMapWidget(
onMapCreated: _onMapCreated, onMapCreated: _onMapCreated,
markers: Set<Marker>.of(_markers.values), markers: Set<Marker>.of(_markers.values),
extensions: [_infoWindowExtension], infoWindowAdapter: CustomInfoWindowAdapter(_controller, selectedMarkerId),
); );
return Container( return Container(
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,
@ -205,7 +196,7 @@ class _State extends State<CustomInfoWindowDemoPage> {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: <Widget>[
Container( Container(
height: MediaQuery.of(context).size.height * 0.6, height: MediaQuery.of(context).size.height * 0.6,
width: MediaQuery.of(context).size.width, width: MediaQuery.of(context).size.width,
@ -221,64 +212,64 @@ class _State extends State<CustomInfoWindowDemoPage> {
Column( Column(
children: <Widget>[ children: <Widget>[
TextButton( TextButton(
child: const Text('添加'),
onPressed: _add, onPressed: _add,
child: const Text('添加'),
), ),
TextButton( TextButton(
child: const Text('移除'),
onPressed: onPressed:
(selectedMarkerId == null) ? null : _remove, (selectedMarkerId == null) ? null : _remove,
child: const Text('移除'),
), ),
TextButton( TextButton(
child: const Text('更新InfoWidow'),
onPressed: onPressed:
(selectedMarkerId == null) ? null : _changeInfo, (selectedMarkerId == null) ? null : _changeInfo,
child: const Text('更新InfoWidow'),
), ),
TextButton( TextButton(
child: const Text('修改锚点'),
onPressed: (selectedMarkerId == null) onPressed: (selectedMarkerId == null)
? null ? null
: _changeAnchor, : _changeAnchor,
child: const Text('修改锚点'),
), ),
TextButton( TextButton(
child: const Text('修改透明度'),
onPressed: (selectedMarkerId == null) onPressed: (selectedMarkerId == null)
? null ? null
: _changeAlpha, : _changeAlpha,
child: const Text('修改透明度'),
), ),
], ],
), ),
Column( Column(
children: <Widget>[ children: <Widget>[
TextButton( TextButton(
onPressed: _markers.isNotEmpty ? _removeAll : null,
child: const Text('全部移除'), child: const Text('全部移除'),
onPressed: _markers.length > 0 ? _removeAll : null,
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('允许拖动'), label: const Text('允许拖动'),
onSwitchChanged: (selectedMarkerId == null) onSwitchChanged: (selectedMarkerId == null)
? null ? null
: _toggleDraggable, : _toggleDraggable,
defaultValue: false, defaultValue: false,
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('显示'), label: const Text('显示'),
onSwitchChanged: (selectedMarkerId == null) onSwitchChanged: (selectedMarkerId == null)
? null ? null
: _toggleVisible, : _toggleVisible,
defaultValue: true, defaultValue: true,
), ),
TextButton( TextButton(
child: const Text('修改坐标'),
onPressed: (selectedMarkerId == null) onPressed: (selectedMarkerId == null)
? null ? null
: _changePosition, : _changePosition,
child: const Text('修改坐标'),
), ),
TextButton( TextButton(
child: const Text('修改旋转角度'),
onPressed: (selectedMarkerId == null) onPressed: (selectedMarkerId == null)
? null ? null
: _changeRotation, : _changeRotation,
child: const Text('修改旋转角度'),
), ),
], ],
), ),
@ -293,3 +284,42 @@ class _State extends State<CustomInfoWindowDemoPage> {
); );
} }
} }
class CustomInfoWindowAdapter extends BaseInfoWindowAdapter {
CustomInfoWindowAdapter(super.controller, this.selectedMarkerId);
final String? selectedMarkerId;
@override
Widget? buildInfoWindowContent(BuildContext context, Marker marker) {
if (marker.id != selectedMarkerId) {
return null;
}
return Container(
padding: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8.0),
boxShadow: <BoxShadow>[
const BoxShadow(
color: Colors.black26,
blurRadius: 4.0,
spreadRadius: 2.0,
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
marker.infoWindow.title ?? 'No Title',
style: const TextStyle(fontWeight: FontWeight.bold),
),
Text(
marker.infoWindow.snippet ?? 'No Snippet',
),
],
),
);
}
}

View File

@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
class MarkerAddAfterMapPage extends StatefulWidget { class MarkerAddAfterMapPage extends StatefulWidget {
@override @override
_BodyState createState() => _BodyState(); State<MarkerAddAfterMapPage> createState() => _BodyState();
} }
class _BodyState extends State<MarkerAddAfterMapPage> { class _BodyState extends State<MarkerAddAfterMapPage> {
@ -14,16 +14,16 @@ class _BodyState extends State<MarkerAddAfterMapPage> {
LatLng _currentLatLng = defaultPosition; LatLng _currentLatLng = defaultPosition;
//添加一个marker //添加一个marker
void _addMarker() { void _addMarker() {
final _markerPosition = final markerPosition =
LatLng(_currentLatLng.latitude, _currentLatLng.longitude + 2 / 1000); LatLng(_currentLatLng.latitude, _currentLatLng.longitude + 2 / 1000);
final Marker marker = Marker( final Marker marker = Marker(
position: _markerPosition, position: markerPosition,
//使用默认hue的方式设置Marker的图标 //使用默认hue的方式设置Marker的图标
icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueOrange), icon: BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueOrange),
); );
//调用setState触发AMapWidget的更新从而完成marker的添加 //调用setState触发AMapWidget的更新从而完成marker的添加
setState(() { setState(() {
_currentLatLng = _markerPosition; _currentLatLng = markerPosition;
//将新的marker添加到map里 //将新的marker添加到map里
_markers[marker.id] = marker; _markers[marker.id] = marker;
}); });
@ -33,16 +33,16 @@ class _BodyState extends State<MarkerAddAfterMapPage> {
return TextButton( return TextButton(
onPressed: onPressed, onPressed: onPressed,
style: ButtonStyle( style: ButtonStyle(
shape: MaterialStateProperty.all( shape: WidgetStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))), RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
//文字颜色 //文字颜色
foregroundColor: MaterialStateProperty.all(Colors.white), foregroundColor: WidgetStateProperty.all(Colors.white),
//水波纹颜色 //水波纹颜色
overlayColor: MaterialStateProperty.all(Colors.blueAccent), overlayColor: WidgetStateProperty.all(Colors.blueAccent),
//背景颜色 //背景颜色
backgroundColor: MaterialStateProperty.resolveWith((states) { backgroundColor: WidgetStateProperty.resolveWith((states) {
//设置按下时的背景颜色 //设置按下时的背景颜色
if (states.contains(MaterialState.pressed)) { if (states.contains(WidgetState.pressed)) {
return Colors.blueAccent; return Colors.blueAccent;
} }
//默认背景颜色 //默认背景颜色

View File

@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
class MarkerAddWithMapPage extends StatefulWidget { class MarkerAddWithMapPage extends StatefulWidget {
@override @override
_BodyState createState() => _BodyState(); State<MarkerAddWithMapPage> createState() => _BodyState();
} }
class _BodyState extends State<MarkerAddWithMapPage> { class _BodyState extends State<MarkerAddWithMapPage> {

View File

@ -19,7 +19,7 @@ class MarkerConfigDemoPage extends StatefulWidget {
class _State extends State<MarkerConfigDemoPage> { class _State extends State<MarkerConfigDemoPage> {
static final LatLng mapCenter = const LatLng(39.909187, 116.397451); static final LatLng mapCenter = const LatLng(39.909187, 116.397451);
Map<String, Marker> _markers = <String, Marker>{}; final Map<String, Marker> _markers = <String, Marker>{};
BitmapDescriptor? _markerIcon; BitmapDescriptor? _markerIcon;
String? selectedMarkerId; String? selectedMarkerId;
@ -27,11 +27,11 @@ class _State extends State<MarkerConfigDemoPage> {
LatLng latLng = LatLng(mapCenter.latitude + sin(pi / 12.0) / 20.0, LatLng latLng = LatLng(mapCenter.latitude + sin(pi / 12.0) / 20.0,
mapCenter.longitude + cos(pi / 12.0) / 20.0); mapCenter.longitude + cos(pi / 12.0) / 20.0);
try { try {
print('-latLng---------${latLng}'); print('-latLng---------$latLng');
ScreenCoordinate coordinate = await controller.toScreenCoordinate(latLng); ScreenCoordinate coordinate = await controller.toScreenCoordinate(latLng);
print('-coordinate---------${coordinate}'); print('-coordinate---------$coordinate');
LatLng reLatLng = await controller.fromScreenCoordinate(coordinate); LatLng reLatLng = await controller.fromScreenCoordinate(coordinate);
print('-reLatLng---------${reLatLng}'); print('-reLatLng---------$reLatLng');
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
} }
@ -85,7 +85,6 @@ class _State extends State<MarkerConfigDemoPage> {
onDragEnd: (markerId, endPosition) => onDragEnd: (markerId, endPosition) =>
_onMarkerDragEnd(markerId, endPosition), _onMarkerDragEnd(markerId, endPosition),
); );
setState(() { setState(() {
_markers[marker.id] = marker; _markers[marker.id] = marker;
}); });
@ -119,7 +118,7 @@ class _State extends State<MarkerConfigDemoPage> {
} }
void _removeAll() { void _removeAll() {
if (_markers.length > 0) { if (_markers.isNotEmpty) {
setState(() { setState(() {
_markers.clear(); _markers.clear();
selectedMarkerId = null.toString(); selectedMarkerId = null.toString();
@ -129,7 +128,7 @@ class _State extends State<MarkerConfigDemoPage> {
void _changeInfo() async { void _changeInfo() async {
final Marker marker = _markers[selectedMarkerId]!; final Marker marker = _markers[selectedMarkerId]!;
final String newTitle = marker.infoWindow.title! + '*'; final String newTitle = '${marker.infoWindow.title!}*';
if (selectedMarkerId != null) { if (selectedMarkerId != null) {
setState(() { setState(() {
_markers[selectedMarkerId!] = marker.copyWith( _markers[selectedMarkerId!] = marker.copyWith(
@ -233,14 +232,12 @@ class _State extends State<MarkerConfigDemoPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
///以下几种获取自定图片的方式使用其中一种即可。 ///以下几种获取自定图片的方式使用其中一种即可。
//最简单的方式 //最简单的方式
if (null == _markerIcon) { _markerIcon ??= BitmapDescriptor.fromIconPath('assets/location_marker.png');
_markerIcon = BitmapDescriptor.fromIconPath('assets/location_marker.png');
}
//通过BitmapDescriptor.fromAssetImage的方式获取图片 //通过BitmapDescriptor.fromAssetImage的方式获取图片
// _createMarkerImageFromAsset(context); _createMarkerImageFromAsset(context);
//通过BitmapDescriptor.fromBytes的方式获取图片 //通过BitmapDescriptor.fromBytes的方式获取图片
// _createMarkerImageFromBytes(context); _createMarkerImageFromBytes(context);
final AMapWidget map = AMapWidget( final AMapWidget map = AMapWidget(
onMapCreated: _onMapCreated, onMapCreated: _onMapCreated,
@ -268,64 +265,64 @@ class _State extends State<MarkerConfigDemoPage> {
Column( Column(
children: <Widget>[ children: <Widget>[
TextButton( TextButton(
child: const Text('添加'),
onPressed: _add, onPressed: _add,
child: const Text('添加'),
), ),
TextButton( TextButton(
child: const Text('移除'),
onPressed: onPressed:
(selectedMarkerId == null) ? null : _remove, (selectedMarkerId == null) ? null : _remove,
child: const Text('移除'),
), ),
TextButton( TextButton(
child: const Text('更新InfoWidow'),
onPressed: onPressed:
(selectedMarkerId == null) ? null : _changeInfo, (selectedMarkerId == null) ? null : _changeInfo,
child: const Text('更新InfoWidow'),
), ),
TextButton( TextButton(
child: const Text('修改锚点'),
onPressed: (selectedMarkerId == null) onPressed: (selectedMarkerId == null)
? null ? null
: _changeAnchor, : _changeAnchor,
child: const Text('修改锚点'),
), ),
TextButton( TextButton(
child: const Text('修改透明度'),
onPressed: (selectedMarkerId == null) onPressed: (selectedMarkerId == null)
? null ? null
: _changeAlpha, : _changeAlpha,
child: const Text('修改透明度'),
), ),
], ],
), ),
Column( Column(
children: <Widget>[ children: <Widget>[
TextButton( TextButton(
onPressed: _markers.isNotEmpty ? _removeAll : null,
child: const Text('全部移除'), child: const Text('全部移除'),
onPressed: _markers.length > 0 ? _removeAll : null,
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('允许拖动'), label: const Text('允许拖动'),
onSwitchChanged: (selectedMarkerId == null) onSwitchChanged: (selectedMarkerId == null)
? null ? null
: _toggleDraggable, : _toggleDraggable,
defaultValue: false, defaultValue: false,
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('显示'), label: const Text('显示'),
onSwitchChanged: (selectedMarkerId == null) onSwitchChanged: (selectedMarkerId == null)
? null ? null
: _toggleVisible, : _toggleVisible,
defaultValue: true, defaultValue: true,
), ),
TextButton( TextButton(
child: const Text('修改坐标'),
onPressed: (selectedMarkerId == null) onPressed: (selectedMarkerId == null)
? null ? null
: _changePosition, : _changePosition,
child: const Text('修改坐标'),
), ),
TextButton( TextButton(
child: const Text('修改旋转角度'),
onPressed: (selectedMarkerId == null) onPressed: (selectedMarkerId == null)
? null ? null
: _changeRotation, : _changeRotation,
child: const Text('修改旋转角度'),
), ),
], ],
), ),

View File

@ -3,17 +3,19 @@ import 'package:x_amap_base/x_amap_base.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class MarkerCustomIconPage extends StatefulWidget { class MarkerCustomIconPage extends StatefulWidget {
const MarkerCustomIconPage({super.key});
@override @override
_BodyState createState() => _BodyState(); State<MarkerCustomIconPage> createState() => _BodyState();
} }
class _BodyState extends State<MarkerCustomIconPage> { class _BodyState extends State<MarkerCustomIconPage> {
static final LatLng markerPosition = const LatLng(39.909187, 116.397451); static const LatLng markerPosition = LatLng(39.909187, 116.397451);
final Map<String, Marker> _initMarkerMap = <String, Marker>{}; final Map<String, Marker> _initMarkerMap = <String, Marker>{};
String? _currentMarkerId; String? _currentMarkerId;
bool _hasInitMarker = false; bool _hasInitMarker = false;
static final String _startIconPath = 'assets/start.png'; static const String _startIconPath = 'assets/start.png';
static final String _endIconPath = 'assets/end.png'; static const String _endIconPath = 'assets/end.png';
String _iconPath = _startIconPath; String _iconPath = _startIconPath;
void _initMarker(BuildContext context) async { void _initMarker(BuildContext context) async {
if (_hasInitMarker) { if (_hasInitMarker) {
@ -42,16 +44,16 @@ class _BodyState extends State<MarkerCustomIconPage> {
return TextButton( return TextButton(
onPressed: onPressed, onPressed: onPressed,
style: ButtonStyle( style: ButtonStyle(
shape: MaterialStateProperty.all( shape: WidgetStateProperty.all(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))), RoundedRectangleBorder(borderRadius: BorderRadius.circular(10))),
//文字颜色 //文字颜色
foregroundColor: MaterialStateProperty.all(Colors.white), foregroundColor: WidgetStateProperty.all(Colors.white),
//水波纹颜色 //水波纹颜色
overlayColor: MaterialStateProperty.all(Colors.blueAccent), overlayColor: WidgetStateProperty.all(Colors.blueAccent),
//背景颜色 //背景颜色
backgroundColor: MaterialStateProperty.resolveWith((states) { backgroundColor: WidgetStateProperty.resolveWith((states) {
//设置按下时的背景颜色 //设置按下时的背景颜色
if (states.contains(MaterialState.pressed)) { if (states.contains(WidgetState.pressed)) {
return Colors.blueAccent; return Colors.blueAccent;
} }
//默认背景颜色 //默认背景颜色

View File

@ -1,6 +1,5 @@
import 'package:amap_map_example/widgets/amap_switch_button.dart'; import 'package:amap_map_example/widgets/amap_switch_button.dart';
import 'package:flutter/material.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 'package:x_amap_base/x_amap_base.dart'; import 'package:x_amap_base/x_amap_base.dart';
@ -24,7 +23,7 @@ class _State extends State<PolygonDemoPage> {
Colors.pink, Colors.pink,
]; ];
Map<String, Polygon> _polygons = <String, Polygon>{}; final Map<String, Polygon> _polygons = <String, Polygon>{};
String? selectedPolygonId; String? selectedPolygonId;
void _onMapCreated(AMapController controller) {} void _onMapCreated(AMapController controller) {}
@ -111,7 +110,7 @@ class _State extends State<PolygonDemoPage> {
List<LatLng> currentPoints = polygon.points; List<LatLng> currentPoints = polygon.points;
List<LatLng> newPoints = <LatLng>[]; List<LatLng> newPoints = <LatLng>[];
newPoints.addAll(currentPoints); newPoints.addAll(currentPoints);
newPoints.add(LatLng(39.828809, 116.360364)); newPoints.add(const LatLng(39.828809, 116.360364));
setState(() { setState(() {
_polygons[selectedPolygonId!] = polygon.copyWith( _polygons[selectedPolygonId!] = polygon.copyWith(
@ -134,7 +133,7 @@ class _State extends State<PolygonDemoPage> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final AMapWidget map = AMapWidget( final AMapWidget map = AMapWidget(
initialCameraPosition: initialCameraPosition:
CameraPosition(target: LatLng(39.828809, 116.360364), zoom: 13), const CameraPosition(target: LatLng(39.828809, 116.360364), zoom: 13),
onMapCreated: _onMapCreated, onMapCreated: _onMapCreated,
polygons: Set<Polygon>.of(_polygons.values), polygons: Set<Polygon>.of(_polygons.values),
); );
@ -160,42 +159,42 @@ class _State extends State<PolygonDemoPage> {
Column( Column(
children: <Widget>[ children: <Widget>[
TextButton( TextButton(
child: const Text('添加'),
onPressed: _add, onPressed: _add,
child: const Text('添加'),
), ),
TextButton( TextButton(
child: const Text('删除'),
onPressed: onPressed:
(selectedPolygonId == null) ? null : _remove, (selectedPolygonId == null) ? null : _remove,
child: const Text('删除'),
), ),
TextButton( TextButton(
child: const Text('修改边框宽度'),
onPressed: (selectedPolygonId == null) onPressed: (selectedPolygonId == null)
? null ? null
: _changeStrokeWidth, : _changeStrokeWidth,
child: const Text('修改边框宽度'),
), ),
], ],
), ),
Column( Column(
children: <Widget>[ children: <Widget>[
TextButton( TextButton(
child: const Text('修改边框和填充色'),
onPressed: (selectedPolygonId == null) onPressed: (selectedPolygonId == null)
? null ? null
: _changeColors, : _changeColors,
child: const Text('修改边框和填充色'),
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('显示'), label: const Text('显示'),
onSwitchChanged: (selectedPolygonId == null) onSwitchChanged: (selectedPolygonId == null)
? null ? null
: _toggleVisible, : _toggleVisible,
defaultValue: true, defaultValue: true,
), ),
TextButton( TextButton(
child: const Text('修改坐标'),
onPressed: (selectedPolygonId == null) onPressed: (selectedPolygonId == null)
? null ? null
: _changePoints, : _changePoints,
child: const Text('修改坐标'),
), ),
], ],
), ),

View File

@ -1,6 +1,5 @@
import 'package:amap_map_example/widgets/amap_switch_button.dart'; import 'package:amap_map_example/widgets/amap_switch_button.dart';
import 'package:flutter/material.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 'package:x_amap_base/x_amap_base.dart'; import 'package:x_amap_base/x_amap_base.dart';
@ -23,7 +22,7 @@ class _State extends State<PolylineDemoPage> {
Colors.green, Colors.green,
Colors.pink, Colors.pink,
]; ];
Map<String, Polyline> _polylines = <String, Polyline>{}; final Map<String, Polyline> _polylines = <String, Polyline>{};
String? selectedPolylineId; String? selectedPolylineId;
void _onMapCreated(AMapController controller) {} void _onMapCreated(AMapController controller) {}
@ -64,7 +63,7 @@ class _State extends State<PolylineDemoPage> {
} }
void _changeWidth() { void _changeWidth() {
final Polyline? selectedPolyline = _polylines[selectedPolylineId]!; final Polyline? selectedPolyline = _polylines[selectedPolylineId];
//有选中的Polyline //有选中的Polyline
if (selectedPolyline != null) { if (selectedPolyline != null) {
double currentWidth = selectedPolyline.width; double currentWidth = selectedPolyline.width;
@ -109,7 +108,7 @@ class _State extends State<PolylineDemoPage> {
} }
void _changeCapType() { void _changeCapType() {
final Polyline? polyline = _polylines[selectedPolylineId]!; final Polyline? polyline = _polylines[selectedPolylineId];
if (polyline == null) { if (polyline == null) {
return; return;
} }
@ -172,7 +171,7 @@ class _State extends State<PolylineDemoPage> {
List<LatLng> currentPoints = polyline.points; List<LatLng> currentPoints = polyline.points;
List<LatLng> newPoints = <LatLng>[]; List<LatLng> newPoints = <LatLng>[];
newPoints.addAll(currentPoints); newPoints.addAll(currentPoints);
newPoints.add(LatLng(39.835347, 116.34575)); newPoints.add(const LatLng(39.835347, 116.34575));
setState(() { setState(() {
_polylines[selectedPolylineId!] = polyline.copyWith( _polylines[selectedPolylineId!] = polyline.copyWith(
@ -219,28 +218,28 @@ class _State extends State<PolylineDemoPage> {
Column( Column(
children: <Widget>[ children: <Widget>[
TextButton( TextButton(
child: const Text('添加'),
onPressed: _add, onPressed: _add,
child: const Text('添加'),
), ),
TextButton( TextButton(
child: const Text('删除'),
onPressed: onPressed:
(selectedPolylineId == null) ? null : _remove, (selectedPolylineId == null) ? null : _remove,
child: const Text('删除'),
), ),
TextButton( TextButton(
child: const Text('修改线宽'),
onPressed: (selectedPolylineId == null) onPressed: (selectedPolylineId == null)
? null ? null
: _changeWidth, : _changeWidth,
child: const Text('修改线宽'),
), ),
TextButton( TextButton(
child: const Text('修改透明度'),
onPressed: (selectedPolylineId == null) onPressed: (selectedPolylineId == null)
? null ? null
: _changeAlpha, : _changeAlpha,
child: const Text('修改透明度'),
), ),
AMapSwitchButton( AMapSwitchButton(
label: Text('显示'), label: const Text('显示'),
onSwitchChanged: (selectedPolylineId == null) onSwitchChanged: (selectedPolylineId == null)
? null ? null
: _toggleVisible, : _toggleVisible,
@ -251,34 +250,34 @@ class _State extends State<PolylineDemoPage> {
Column( Column(
children: <Widget>[ children: <Widget>[
TextButton( TextButton(
child: const Text('修改颜色'),
onPressed: (selectedPolylineId == null) onPressed: (selectedPolylineId == null)
? null ? null
: _changeColor, : _changeColor,
child: const Text('修改颜色'),
), ),
TextButton( TextButton(
child: const Text('修改线头样式'),
onPressed: (selectedPolylineId == null) onPressed: (selectedPolylineId == null)
? null ? null
: _changeCapType, : _changeCapType,
child: const Text('修改线头样式'),
), ),
TextButton( TextButton(
child: const Text('修改连接样式'),
onPressed: (selectedPolylineId == null) onPressed: (selectedPolylineId == null)
? null ? null
: _changeJointType, : _changeJointType,
child: const Text('修改连接样式'),
), ),
TextButton( TextButton(
child: const Text('修改虚线类型'),
onPressed: (selectedPolylineId == null) onPressed: (selectedPolylineId == null)
? null ? null
: _changeDashLineType, : _changeDashLineType,
child: const Text('修改虚线类型'),
), ),
TextButton( TextButton(
child: const Text('修改坐标'),
onPressed: (selectedPolylineId == null) onPressed: (selectedPolylineId == null)
? null ? null
: _changePoints, : _changePoints,
child: const Text('修改坐标'),
), ),
], ],
), ),

View File

@ -1,5 +1,4 @@
import 'package:flutter/material.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 'package:x_amap_base/x_amap_base.dart'; import 'package:x_amap_base/x_amap_base.dart';
@ -22,7 +21,7 @@ class _State extends State<PolylineGeodesicDemoPage> {
Colors.green, Colors.green,
Colors.pink, Colors.pink,
]; ];
Map<String, Polyline> _polylines = <String, Polyline>{}; final Map<String, Polyline> _polylines = <String, Polyline>{};
late String selectedPolylineId; late String selectedPolylineId;
AMapController? _controller; AMapController? _controller;
@ -89,16 +88,16 @@ class _State extends State<PolylineGeodesicDemoPage> {
child: TextButton( child: TextButton(
onPressed: _add, onPressed: _add,
style: ButtonStyle( style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder( shape: WidgetStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10))), borderRadius: BorderRadius.circular(10))),
//文字颜色 //文字颜色
foregroundColor: MaterialStateProperty.all(Colors.white), foregroundColor: WidgetStateProperty.all(Colors.white),
//水波纹颜色 //水波纹颜色
overlayColor: MaterialStateProperty.all(Colors.blueAccent), overlayColor: WidgetStateProperty.all(Colors.blueAccent),
//背景颜色 //背景颜色
backgroundColor: MaterialStateProperty.resolveWith((states) { backgroundColor: WidgetStateProperty.resolveWith((states) {
//设置按下时的背景颜色 //设置按下时的背景颜色
if (states.contains(MaterialState.pressed)) { if (states.contains(WidgetState.pressed)) {
return Colors.blueAccent; return Colors.blueAccent;
} }
//默认背景颜色 //默认背景颜色

View File

@ -13,7 +13,7 @@ class PolylineTextureDemoPage extends StatefulWidget {
class _State extends State<PolylineTextureDemoPage> { class _State extends State<PolylineTextureDemoPage> {
_State(); _State();
Map<String, Polyline> _polylines = <String, Polyline>{}; final Map<String, Polyline> _polylines = <String, Polyline>{};
late String selectedPolylineId; late String selectedPolylineId;
void _onMapCreated(AMapController controller) {} void _onMapCreated(AMapController controller) {}
@ -76,16 +76,16 @@ class _State extends State<PolylineTextureDemoPage> {
child: TextButton( child: TextButton(
onPressed: _add, onPressed: _add,
style: ButtonStyle( style: ButtonStyle(
shape: MaterialStateProperty.all(RoundedRectangleBorder( shape: WidgetStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10))), borderRadius: BorderRadius.circular(10))),
//文字颜色 //文字颜色
foregroundColor: MaterialStateProperty.all(Colors.white), foregroundColor: WidgetStateProperty.all(Colors.white),
//水波纹颜色 //水波纹颜色
overlayColor: MaterialStateProperty.all(Colors.blueAccent), overlayColor: WidgetStateProperty.all(Colors.blueAccent),
//背景颜色 //背景颜色
backgroundColor: MaterialStateProperty.resolveWith((states) { backgroundColor: WidgetStateProperty.resolveWith((states) {
//设置按下时的背景颜色 //设置按下时的背景颜色
if (states.contains(MaterialState.pressed)) { if (states.contains(WidgetState.pressed)) {
return Colors.blueAccent; return Colors.blueAccent;
} }
//默认背景颜色 //默认背景颜色

View File

@ -23,7 +23,7 @@ class Path {
} }
class RouteConfig { class RouteConfig {
static List<Path> _paths = [ static final List<Path> _paths = [
Path( Path(
r'^/([\w-]+)$', r'^/([\w-]+)$',
(context, match) => DemoPage(slug: match), (context, match) => DemoPage(slug: match),

View File

@ -1,20 +0,0 @@
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

@ -11,13 +11,12 @@ class AMapGradView extends StatefulWidget {
final double? childAspectRatio; final double? childAspectRatio;
AMapGradView( AMapGradView(
{Key? key, {super.key,
this.crossAxisCount, this.crossAxisCount,
this.childAspectRatio, this.childAspectRatio,
required this.childrenWidgets}) required this.childrenWidgets});
: super(key: key);
@override @override
_GradViewState createState() => _GradViewState(); State<AMapGradView> createState() => _GradViewState();
} }
class _GradViewState extends State<AMapGradView> { class _GradViewState extends State<AMapGradView> {
@ -25,7 +24,7 @@ class _GradViewState extends State<AMapGradView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GridView.count( return GridView.count(
primary: false, primary: false,
physics: new NeverScrollableScrollPhysics(), physics: NeverScrollableScrollPhysics(),
//水平子Widget之间间距 //水平子Widget之间间距
crossAxisSpacing: 1.0, crossAxisSpacing: 1.0,
//垂直子Widget之间间距 //垂直子Widget之间间距

View File

@ -7,15 +7,14 @@ class AMapRadioGroup<T> extends StatefulWidget {
final Map<String, T>? radioValueMap; final Map<String, T>? radioValueMap;
final ValueChanged<T?>? onChanged; final ValueChanged<T?>? onChanged;
AMapRadioGroup( AMapRadioGroup(
{Key? key, {super.key,
this.groupLabel, this.groupLabel,
this.groupValue, this.groupValue,
this.radioValueMap, this.radioValueMap,
this.onChanged}) this.onChanged});
: super(key: key);
@override @override
_AMapRadioGroupState<T> createState() => _AMapRadioGroupState<T>(); State<AMapRadioGroup<T>> createState() => _AMapRadioGroupState<T>();
} }
class _AMapRadioGroupState<T> extends State<AMapRadioGroup<T>> { class _AMapRadioGroupState<T> extends State<AMapRadioGroup<T>> {
@ -24,14 +23,14 @@ class _AMapRadioGroupState<T> extends State<AMapRadioGroup<T>> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_groupValue = (widget.groupValue ?? null) as T?; _groupValue = (widget.groupValue);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Widget> radioList = <Widget>[]; List<Widget> radioList = <Widget>[];
_groupValue = (widget.groupValue ?? null) as T?; _groupValue = (widget.groupValue);
Widget _myRadio(String label, dynamic radioValue) { Widget myRadio(String label, dynamic radioValue) {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@ -39,11 +38,11 @@ class _AMapRadioGroupState<T> extends State<AMapRadioGroup<T>> {
Radio<T>( Radio<T>(
value: radioValue, value: radioValue,
groupValue: _groupValue, groupValue: _groupValue,
onChanged: (T? _value) { onChanged: (T? value) {
setState(() { setState(() {
_groupValue = _value; _groupValue = value;
}); });
widget.onChanged!(_value); widget.onChanged!(value);
}, },
), ),
], ],
@ -52,7 +51,7 @@ class _AMapRadioGroupState<T> extends State<AMapRadioGroup<T>> {
if (widget.radioValueMap != null) { if (widget.radioValueMap != null) {
widget.radioValueMap!.forEach((key, value) { widget.radioValueMap!.forEach((key, value) {
radioList.add(_myRadio(key, value)); radioList.add(myRadio(key, value));
}); });
} }
return Container( return Container(

View File

@ -1,14 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
typedef void OnChanged(bool value); typedef OnChanged = void Function(bool value);
class AMapSwitchButton extends StatefulWidget { class AMapSwitchButton extends StatefulWidget {
const AMapSwitchButton({ const AMapSwitchButton({
Key? key, super.key,
this.label, this.label,
this.onSwitchChanged, this.onSwitchChanged,
this.defaultValue = true, this.defaultValue = true,
}) : super(key: key); });
final Text? label; final Text? label;
final Function? onSwitchChanged; final Function? onSwitchChanged;

View File

@ -3,7 +3,7 @@ description: Demonstrates how to use the amap_map plugin.
# The following line prevents the package from being accidentally published to # The following line prevents the package from being accidentally published to
# pub.dev using `pub publish`. This is preferred for private packages. # pub.dev using `pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev publish_to: "none" # Remove this line if you wish to publish to pub.dev
environment: environment:
sdk: ">=3.1.5 <4.0.0" sdk: ">=3.1.5 <4.0.0"
@ -12,22 +12,12 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
permission_handler: ^11.3.0 permission_handler: ^11.3.1
flutter_plugin_android_lifecycle: ^2.0.17
amap_map: amap_map:
# When depending on this package from a real application you should use:
# amap_map: ^x.y.z
# See https://dart.dev/tools/pub/dependencies#version-constraints
# The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version.
path: ../ path: ../
x_common: ^1.0.4 x_common: ^1.0.4
x_amap_base: ^1.0.3
# amap_map_extensions: ^0.0.1
# amap_map_extensions:
# path: ../../amap_map_extensions
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -38,7 +28,6 @@ dev_dependencies:
# The following section is specific to Flutter. # The following section is specific to Flutter.
flutter: flutter:
# The following line ensures that the Material Icons font is # The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in # included with your application, so that you can use the icons in
# the material Icons class. # the material Icons class.
@ -50,5 +39,3 @@ flutter:
# assets: # assets:
# - images/a_dot_burr.jpeg # - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg

View File

@ -3,36 +3,36 @@ import 'package:x_amap_base/x_amap_base.dart';
void main() { void main() {
test('Distance between two different point', () { test('Distance between two different point', () {
LatLng p1 = LatLng(1, 1); LatLng p1 = const LatLng(1, 1);
LatLng p2 = LatLng(2, 2); LatLng p2 = const LatLng(2, 2);
double distance = AMapTools.distanceBetween(p1, p2); double distance = AMapTools.distanceBetween(p1, p2);
expect(distance, 157401.56104583555); expect(distance, 157401.56104583555);
}); });
test('Distance between two same point', () { test('Distance between two same point', () {
LatLng p1 = LatLng(1, 1); LatLng p1 = const LatLng(1, 1);
LatLng p2 = LatLng(1, 1); LatLng p2 = const LatLng(1, 1);
double distance = AMapTools.distanceBetween(p1, p2); double distance = AMapTools.distanceBetween(p1, p2);
expect(distance, 0); expect(distance, 0);
}); });
test('Distance between two different point with equal lat', () { test('Distance between two different point with equal lat', () {
LatLng p1 = LatLng(1, 1); LatLng p1 = const LatLng(1, 1);
LatLng p2 = LatLng(1, 2); LatLng p2 = const LatLng(1, 2);
double distance = AMapTools.distanceBetween(p1, p2); double distance = AMapTools.distanceBetween(p1, p2);
expect(distance, 111302.53586533663); expect(distance, 111302.53586533663);
}); });
test('Distance between two different point with equal lng', () { test('Distance between two different point with equal lng', () {
LatLng p1 = LatLng(1, 1); LatLng p1 = const LatLng(1, 1);
LatLng p2 = LatLng(2, 1); LatLng p2 = const LatLng(2, 1);
double distance = AMapTools.distanceBetween(p1, p2); double distance = AMapTools.distanceBetween(p1, p2);
expect(distance, 111319.49079327357); expect(distance, 111319.49079327357);
}); });
test('Distance between two different point with close point', () { test('Distance between two different point with close point', () {
LatLng p1 = LatLng(39.938212, 116.455139); LatLng p1 = const LatLng(39.938212, 116.455139);
LatLng p2 = LatLng(39.987656, 116.265605); LatLng p2 = const LatLng(39.987656, 116.265605);
double distance = AMapTools.distanceBetween(p1, p2); double distance = AMapTools.distanceBetween(p1, p2);
expect(distance, 17082.425889709597); expect(distance, 17082.425889709597);
}); });

View File

@ -262,6 +262,15 @@
// logo // logo
self.logoCenter = logoCenter; self.logoCenter = logoCenter;
//
NSString *mapLanguage = dict[@"mapLanguage"];
// :@0: :@1. 使1使2MAMapTypeStandard
if ([mapLanguage isEqualToString:@"zh_cn"]) {
self.mapLanguage = @0;
} else if ([mapLanguage isEqualToString:@"en"]) {
self.mapLanguage = @1;
}
} }
@end @end

View File

@ -11,7 +11,7 @@
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
/// 高德地图Flutter插件入口文件 /// 高德地图Flutter插件入口文件
library amap_map; library;
import 'dart:async'; import 'dart:async';
@ -24,12 +24,10 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:x_common/utils/logger.dart';
export 'package:amap_map/src/types/types.dart'; export 'package:amap_map/src/types/types.dart';
part 'src/amap_initializer.dart'; part 'src/amap_initializer.dart';
part 'src/amap_controller.dart'; part 'src/amap_controller.dart';
part 'src/amap_widget.dart'; part 'src/amap_widget.dart';
part 'src/amap_loader.dart';
part 'src/utils/location_utils.dart'; part 'src/utils/location_utils.dart';

View File

@ -10,7 +10,7 @@
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
part of amap_map; part of '../amap_map.dart';
final MethodChannelAMapFlutterMap _methodChannel = final MethodChannelAMapFlutterMap _methodChannel =
AMapFlutterPlatform.instance as MethodChannelAMapFlutterMap; AMapFlutterPlatform.instance as MethodChannelAMapFlutterMap;
@ -30,7 +30,7 @@ class AMapController {
static Future<AMapController> init( static Future<AMapController> init(
int id, int id,
CameraPosition initialCameration, CameraPosition initialCameration,
_MapState mapState, mapState,
) async { ) async {
await _methodChannel.init(id); await _methodChannel.init(id);
return AMapController._( return AMapController._(
@ -55,48 +55,42 @@ class AMapController {
_methodChannel _methodChannel
.onCameraMove(mapId: mapId) .onCameraMove(mapId: mapId)
.listen((CameraPositionMoveEvent e) { .listen((CameraPositionMoveEvent e) {
_mapState._extensions.values.forEach((ext) => ext.onCameraMove(e.value));
_mapState.widget.onCameraMove?.call(e.value); _mapState.widget.onCameraMove?.call(e.value);
if (_mapState.widget.infoWindowAdapter != null) {
_mapState.updateMarkers();
}
}); });
_methodChannel _methodChannel
.onCameraMoveEnd(mapId: mapId) .onCameraMoveEnd(mapId: mapId)
.listen((CameraPositionMoveEndEvent e) { .listen((CameraPositionMoveEndEvent e) {
_mapState._extensions.values
.forEach((ext) => ext.onCameraMoveEnd(e.value));
_mapState.widget.onCameraMoveEnd?.call(e.value); _mapState.widget.onCameraMoveEnd?.call(e.value);
}); });
_methodChannel _methodChannel
.onMapTap(mapId: mapId) .onMapTap(mapId: mapId)
.listen(((MapTapEvent e) => _mapState.widget.onTap?.call(e.value))); .listen(((MapTapEvent e) => _mapState.widget.onTap?.call(e.value)));
_methodChannel.onMapLongPress(mapId: mapId).listen(((MapLongPressEvent e) { _methodChannel.onMapLongPress(mapId: mapId).listen(((MapLongPressEvent e) {
_mapState._extensions.values.forEach((ext) => ext.onLongPress(e.value));
_mapState.widget.onLongPress?.call(e.value); _mapState.widget.onLongPress?.call(e.value);
})); }));
_methodChannel.onPoiTouched(mapId: mapId).listen(((MapPoiTouchEvent e) { _methodChannel.onPoiTouched(mapId: mapId).listen(((MapPoiTouchEvent e) {
_mapState._extensions.values.forEach((ext) => ext.onPoiTouched(e.value));
_mapState.widget.onPoiTouched?.call(e.value); _mapState.widget.onPoiTouched?.call(e.value);
})); }));
_methodChannel.onMarkerTap(mapId: mapId).listen((MarkerTapEvent e) { _methodChannel.onMarkerTap(mapId: mapId).listen((MarkerTapEvent e) {
_mapState._extensions.values.forEach((ext) => ext.onMarkerTap(e.value));
_mapState.onMarkerTap(e.value); _mapState.onMarkerTap(e.value);
}); });
_methodChannel.onMarkerDragEnd(mapId: mapId).listen((MarkerDragEndEvent e) { _methodChannel.onMarkerDragEnd(mapId: mapId).listen((MarkerDragEndEvent e) {
_mapState._extensions.values
.forEach((ext) => ext.onMarkerDragEnd(e.value));
_mapState.onMarkerDragEnd(e.value, e.position); _mapState.onMarkerDragEnd(e.value, e.position);
}); });
_methodChannel.onPolylineTap(mapId: mapId).listen((PolylineTapEvent e) { _methodChannel.onPolylineTap(mapId: mapId).listen((PolylineTapEvent e) {
_mapState._extensions.values.forEach((ext) => ext.onPolylineTap(e.value));
_mapState.onPolylineTap(e.value); _mapState.onPolylineTap(e.value);
}); });
} }
void disponse() { void dispose() {
_methodChannel.dispose(id: mapId); _methodChannel.dispose(id: mapId);
} }
@ -150,4 +144,12 @@ class AMapController {
Future<LatLng> fromScreenCoordinate(ScreenCoordinate screenCoordinate) { Future<LatLng> fromScreenCoordinate(ScreenCoordinate screenCoordinate) {
return _methodChannel.fromScreenLocation(screenCoordinate, mapId: mapId); return _methodChannel.fromScreenLocation(screenCoordinate, mapId: mapId);
} }
Future<String> getMapContentApprovalNumber() {
return _methodChannel.getMapContentApprovalNumber(mapId: mapId);
}
Future<String> getSatelliteImageApprovalNumber() {
return _methodChannel.getSatelliteImageApprovalNumber(mapId: mapId);
}
} }

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
part of amap_map; part of '../amap_map.dart';
class AMapInitializer { class AMapInitializer {
static AMapApiKey? _apiKey; static AMapApiKey? _apiKey;

View File

@ -1,94 +0,0 @@
// Copyright 2023-2024 kuloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
part of amap_map;
/// 加载器,在[AMapWidget]的生命周期上绑定拓展
class AMapLoader extends StatefulWidget {
const AMapLoader(
{super.key, required this.mapView, required this.extensions});
final Widget mapView;
final List<AMapExtension> extensions;
@override
State<AMapLoader> createState() => _AMapLoaderState();
static void prepare() {
// TODO Loader 初始化静态方法在initState时做些逻辑
}
/// 传递构建视图,拓展按需进行包装和挂载定制视图
Widget buildFromExtension(AMapContext aMapContext) {
Widget child = mapView;
for (var e in extensions) {
child = e.build(aMapContext, child);
}
return child;
}
/// [didChangeDependencies] 状态更新时,挨个遍历进行拓展的更新操作
void prepareFromExtension(AMapContext aMapContext) {
for (var e in extensions) {
e.prepare(aMapContext);
}
}
/// [didChangeDependencies] 状态更新时,挨个遍历进行拓展的更新操作
void updateFromExtension(AMapContext aMapContext) {
for (var e in extensions) {
e.update(aMapContext);
}
// Future.forEach(extensions, (ext) => ext.update(aMapContext));
}
}
class _AMapLoaderState extends State<AMapLoader> {
@override
void didChangeDependencies() {
final aMapContext = AMapContext(
buildContext: context,
currentStep: CurrentStep.preparing,
loader: widget);
widget.prepareFromExtension(aMapContext);
super.didChangeDependencies();
}
@override
void didUpdateWidget(covariant AMapLoader oldWidget) {
final aMapContext = AMapContext(
buildContext: context,
currentStep: CurrentStep.updating,
loader: widget);
widget.updateFromExtension(aMapContext);
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
for (var e in widget.extensions) {
e.onDispose();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
// Set the extension context for this node.
final aMapContext = AMapContext(
buildContext: context,
currentStep: CurrentStep.building,
loader: widget);
return widget.buildFromExtension(aMapContext);
}
}

View File

@ -10,9 +10,9 @@
// Unless required by applicable law or agreed to in writing, software // Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
part of amap_map; part of '../amap_map.dart';
typedef void MapCreatedCallback(AMapController controller); typedef MapCreatedCallback = void Function(AMapController controller);
///用于展示高德地图的Widget ///用于展示高德地图的Widget
class AMapWidget extends StatefulWidget { class AMapWidget extends StatefulWidget {
@ -106,7 +106,11 @@ class AMapWidget extends StatefulWidget {
///需要应用到地图上的手势集合 ///需要应用到地图上的手势集合
final Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers; final Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers;
final List<AMapExtension> extensions; /// 设置地图语言
final MapLanguage? mapLanguage;
/// Marker InfoWindow 适配器
final InfoWindowAdapter? infoWindowAdapter;
/// 创建一个展示高德地图的widget /// 创建一个展示高德地图的widget
/// ///
@ -120,7 +124,7 @@ class AMapWidget extends StatefulWidget {
/// ///
/// [AssertionError] will be thrown if [initialCameraPosition] is null; /// [AssertionError] will be thrown if [initialCameraPosition] is null;
const AMapWidget( const AMapWidget(
{Key? key, {super.key,
this.initialCameraPosition = this.initialCameraPosition =
const CameraPosition(target: LatLng(39.909187, 116.397451), zoom: 10), const CameraPosition(target: LatLng(39.909187, 116.397451), zoom: 10),
this.mapType = MapType.normal, this.mapType = MapType.normal,
@ -149,11 +153,11 @@ class AMapWidget extends StatefulWidget {
this.markers = const <Marker>{}, this.markers = const <Marker>{},
this.polylines = const <Polyline>{}, this.polylines = const <Polyline>{},
this.polygons = const <Polygon>{}, this.polygons = const <Polygon>{},
this.extensions = const [], this.mapLanguage,
this.infoWindowAdapter,
this.logoPosition, this.logoPosition,
this.logoBottomMargin, this.logoBottomMargin,
this.logoLeftMargin}) this.logoLeftMargin});
: super(key: key);
/// ///
@override @override
@ -164,7 +168,7 @@ class _MapState extends State<AMapWidget> {
Map<String, Marker> _markers = <String, Marker>{}; Map<String, Marker> _markers = <String, Marker>{};
Map<String, Polyline> _polylines = <String, Polyline>{}; Map<String, Polyline> _polylines = <String, Polyline>{};
Map<String, Polygon> _polygons = <String, Polygon>{}; Map<String, Polygon> _polygons = <String, Polygon>{};
Map<String, AMapExtension> _extensions = <String, AMapExtension>{}; final Map<String, Widget?> _infoWindows = <String, Widget?>{};
final Completer<AMapController> _controller = Completer<AMapController>(); final Completer<AMapController> _controller = Completer<AMapController>();
late _AMapOptions _mapOptions; late _AMapOptions _mapOptions;
@ -186,22 +190,19 @@ class _MapState extends State<AMapWidget> {
onPlatformViewCreated, onPlatformViewCreated,
); );
return AMapLoader( return Stack(
mapView: mapView, children: [mapView, ..._infoWindows.values.nonNulls],
extensions: widget.extensions,
); );
} }
@override @override
void initState() { void initState() {
AMapLoader.prepare();
super.initState(); super.initState();
_mapOptions = _AMapOptions.fromWidget(widget); _mapOptions = _AMapOptions.fromWidget(widget);
_markers = keyByMarkerId(widget.markers); _markers = keyByMarkerId(widget.markers);
_polygons = keyByPolygonId(widget.polygons); _polygons = keyByPolygonId(widget.polygons);
_polylines = keyByPolylineId(widget.polylines); _polylines = keyByPolylineId(widget.polylines);
_extensions = keyByExtensionId(widget.extensions);
print('initState AMapWidget'); print('initState AMapWidget');
} }
@ -209,7 +210,7 @@ class _MapState extends State<AMapWidget> {
void dispose() async { void dispose() async {
super.dispose(); super.dispose();
AMapController controller = await _controller.future; AMapController controller = await _controller.future;
controller.disponse(); controller.dispose();
print('dispose AMapWidget with mapId: ${controller.mapId}'); print('dispose AMapWidget with mapId: ${controller.mapId}');
} }
@ -222,17 +223,16 @@ class _MapState extends State<AMapWidget> {
@override @override
void deactivate() async { void deactivate() async {
super.deactivate(); super.deactivate();
print('deactivate AMapWidget}'); print('deactivate AMapWidget');
} }
@override @override
void didUpdateWidget(covariant AMapWidget oldWidget) { void didUpdateWidget(covariant AMapWidget oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
_updateOptions(); _updateOptions();
_updateMarkers(); updateMarkers();
_updatePolylines(); _updatePolylines();
_updatePolygons(); _updatePolygons();
_updateExtensions();
} }
Future<void> onPlatformViewCreated(int id) async { Future<void> onPlatformViewCreated(int id) async {
@ -243,46 +243,38 @@ class _MapState extends State<AMapWidget> {
); );
_controller.complete(controller); _controller.complete(controller);
if (_extensions.isNotEmpty) { final MapCreatedCallback? onMapCreated = widget.onMapCreated;
debugPrint('[onPlatformViewCreated] $controller'); if (onMapCreated != null) {
await Future.forEach(_extensions.values, (e) { onMapCreated(controller);
e.bindMethodChannel(controller.channel);
e.bindMapController(controller);
});
}
final MapCreatedCallback? _onMapCreated = widget.onMapCreated;
if (_onMapCreated != null) {
_onMapCreated(controller);
} }
} }
void onMarkerTap(String markerId) { void onMarkerTap(String markerId) {
final Marker? _marker = _markers[markerId]; final Marker? marker = _markers[markerId];
if (_marker != null) { if (marker != null) {
final ArgumentCallback<String>? _onTap = _marker.onTap; final ArgumentCallback<String>? onTap = marker.onTap;
if (_onTap != null) { if (onTap != null) {
_onTap(markerId); onTap(markerId);
} }
} }
} }
void onMarkerDragEnd(String markerId, LatLng position) { void onMarkerDragEnd(String markerId, LatLng position) {
final Marker? _marker = _markers[markerId]; final Marker? marker = _markers[markerId];
if (_marker != null) { if (marker != null) {
final MarkerDragEndCallback? _onDragEnd = _marker.onDragEnd; final MarkerDragEndCallback? onDragEnd = marker.onDragEnd;
if (_onDragEnd != null) { if (onDragEnd != null) {
_onDragEnd(markerId, position); onDragEnd(markerId, position);
} }
} }
} }
void onPolylineTap(String polylineId) { void onPolylineTap(String polylineId) {
final Polyline? _polyline = _polylines[polylineId]; final Polyline? polyline = _polylines[polylineId];
if (_polyline != null) { if (polyline != null) {
final ArgumentCallback<String>? _onTap = _polyline.onTap; final ArgumentCallback<String>? onTap = polyline.onTap;
if (_onTap != null) { if (onTap != null) {
_onTap(polylineId); onTap(polylineId);
} }
} }
} }
@ -299,12 +291,24 @@ class _MapState extends State<AMapWidget> {
_mapOptions = newOptions; _mapOptions = newOptions;
} }
void _updateMarkers() async { void updateMarkers() async {
final AMapController controller = await _controller.future; final AMapController controller = await _controller.future;
MarkerUpdates markerUpdates =
MarkerUpdates.from(_markers.values.toSet(), widget.markers);
markerUpdates.markerIdsToRemove?.forEach((markerId) {
_removeInfoWindow(markerId);
});
// ignore: unawaited_futures // ignore: unawaited_futures
controller._updateMarkers( controller._updateMarkers(markerUpdates);
MarkerUpdates.from(_markers.values.toSet(), widget.markers));
_markers = keyByMarkerId(widget.markers); _markers = keyByMarkerId(widget.markers);
if (widget.infoWindowAdapter != null) {
for (var marker in _markers.values) {
_onInfoWindowUpdate(marker);
}
}
} }
void _updatePolylines() async { void _updatePolylines() async {
@ -321,9 +325,19 @@ class _MapState extends State<AMapWidget> {
_polygons = keyByPolygonId(widget.polygons); _polygons = keyByPolygonId(widget.polygons);
} }
void _updateExtensions() async { void _onInfoWindowUpdate(Marker marker) {
// final AMapController controller = await _controller.future; if (widget.infoWindowAdapter != null) {
_extensions = keyByExtensionId(widget.extensions); setState(() {
_infoWindows[marker.id] =
widget.infoWindowAdapter!.getInfoWindow(context, marker);
});
}
}
void _removeInfoWindow(String markerId) {
setState(() {
_infoWindows.remove(markerId);
});
} }
} }
@ -380,8 +394,10 @@ class _AMapOptions {
final int? logoBottomMargin; final int? logoBottomMargin;
final int? logoLeftMargin; final int? logoLeftMargin;
_AMapOptions({ final MapLanguage? mapLanguage;
this.mapType = MapType.normal,
_AMapOptions(
{this.mapType = MapType.normal,
this.buildingsEnabled, this.buildingsEnabled,
this.customStyleOptions, this.customStyleOptions,
this.myLocationStyleOptions, this.myLocationStyleOptions,
@ -399,7 +415,7 @@ class _AMapOptions {
this.logoPosition, this.logoPosition,
this.logoBottomMargin, this.logoBottomMargin,
this.logoLeftMargin, this.logoLeftMargin,
}); this.mapLanguage});
static _AMapOptions fromWidget(AMapWidget map) { static _AMapOptions fromWidget(AMapWidget map) {
return _AMapOptions( return _AMapOptions(
@ -420,7 +436,9 @@ class _AMapOptions {
myLocationStyleOptions: map.myLocationStyleOptions?.clone(), myLocationStyleOptions: map.myLocationStyleOptions?.clone(),
logoPosition: map.logoPosition?.index, logoPosition: map.logoPosition?.index,
logoBottomMargin: map.logoBottomMargin, logoBottomMargin: map.logoBottomMargin,
logoLeftMargin: map.logoLeftMargin); logoLeftMargin: map.logoLeftMargin,
mapLanguage: map.mapLanguage,
);
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
@ -449,6 +467,7 @@ class _AMapOptions {
addIfNonNull('logoPosition', logoPosition); addIfNonNull('logoPosition', logoPosition);
addIfNonNull('logoBottomMargin', logoBottomMargin); addIfNonNull('logoBottomMargin', logoBottomMargin);
addIfNonNull('logoLeftMargin', logoLeftMargin); addIfNonNull('logoLeftMargin', logoLeftMargin);
addIfNonNull('mapLanguage', mapLanguage?.value);
return optionsMap; return optionsMap;
} }

View File

@ -18,29 +18,27 @@ class MapEvent<T> {
///定位回调接口 ///定位回调接口
class LocationChangedEvent extends MapEvent<AMapLocation> { class LocationChangedEvent extends MapEvent<AMapLocation> {
LocationChangedEvent(int mapId, AMapLocation value) : super(mapId, value); LocationChangedEvent(super.mapId, super.value);
} }
///地图移动回调 ///地图移动回调
class CameraPositionMoveEvent extends MapEvent<CameraPosition> { class CameraPositionMoveEvent extends MapEvent<CameraPosition> {
CameraPositionMoveEvent(int mapId, CameraPosition value) CameraPositionMoveEvent(super.mapId, super.value);
: super(mapId, value);
} }
///地图移动结束回调 ///地图移动结束回调
class CameraPositionMoveEndEvent extends MapEvent<CameraPosition> { class CameraPositionMoveEndEvent extends MapEvent<CameraPosition> {
CameraPositionMoveEndEvent(int mapId, CameraPosition value) CameraPositionMoveEndEvent(super.mapId, super.value);
: super(mapId, value);
} }
///点击地图回调 ///点击地图回调
class MapTapEvent extends MapEvent<LatLng> { class MapTapEvent extends MapEvent<LatLng> {
MapTapEvent(int mapId, LatLng value) : super(mapId, value); MapTapEvent(super.mapId, super.value);
} }
///长按地图回调 ///长按地图回调
class MapLongPressEvent extends MapEvent<LatLng> { class MapLongPressEvent extends MapEvent<LatLng> {
MapLongPressEvent(int mapId, LatLng value) : super(mapId, value); MapLongPressEvent(super.mapId, super.value);
} }
/// 带位置回调的地图事件 /// 带位置回调的地图事件
@ -57,21 +55,20 @@ class _PositionedMapEvent<T> extends MapEvent<T> {
/// [Marker] 的点击事件 /// [Marker] 的点击事件
class MarkerTapEvent extends MapEvent<String> { class MarkerTapEvent extends MapEvent<String> {
MarkerTapEvent(int mapId, String markerId) : super(mapId, markerId); MarkerTapEvent(super.mapId, super.markerId);
} }
/// [Marker] 的拖拽结束事件,附带拖拽结束时的位置信息[LatLng]. /// [Marker] 的拖拽结束事件,附带拖拽结束时的位置信息[LatLng].
class MarkerDragEndEvent extends _PositionedMapEvent<String> { class MarkerDragEndEvent extends _PositionedMapEvent<String> {
MarkerDragEndEvent(int mapId, LatLng position, String markerId) MarkerDragEndEvent(super.mapId, super.position, super.markerId);
: super(mapId, position, markerId);
} }
/// [Polyline] 的点击事件 /// [Polyline] 的点击事件
class PolylineTapEvent extends MapEvent<String> { class PolylineTapEvent extends MapEvent<String> {
PolylineTapEvent(int mapId, String polylineId) : super(mapId, polylineId); PolylineTapEvent(super.mapId, super.polylineId);
} }
/// Poi点击事件 /// Poi点击事件
class MapPoiTouchEvent extends MapEvent<AMapPoi> { class MapPoiTouchEvent extends MapEvent<AMapPoi> {
MapPoiTouchEvent(int mapId, AMapPoi poi) : super(mapId, poi); MapPoiTouchEvent(super.mapId, super.poi);
} }

View File

@ -23,6 +23,7 @@ import 'package:stream_transform/stream_transform.dart';
import 'map_event.dart'; import 'map_event.dart';
// ignore: constant_identifier_names
const VIEW_TYPE = 'com.amap.flutter.map'; const VIEW_TYPE = 'com.amap.flutter.map';
/// 使用[MethodChannel]与Native代码通信的[AMapFlutterPlatform]的实现。 /// 使用[MethodChannel]与Native代码通信的[AMapFlutterPlatform]的实现。
@ -182,7 +183,7 @@ class MethodChannelAMapFlutterMap implements AMapFlutterPlatform {
_mapEventStreamController.add(LocationChangedEvent( _mapEventStreamController.add(LocationChangedEvent(
mapId, AMapLocation.fromMap(call.arguments['location'])!)); mapId, AMapLocation.fromMap(call.arguments['location'])!));
} catch (e) { } catch (e) {
print("location#changed error=======>" + e.toString()); print("location#changed error=======>$e");
} }
break; break;
@ -191,7 +192,7 @@ class MethodChannelAMapFlutterMap implements AMapFlutterPlatform {
_mapEventStreamController.add(CameraPositionMoveEvent( _mapEventStreamController.add(CameraPositionMoveEvent(
mapId, CameraPosition.fromMap(call.arguments['position'])!)); mapId, CameraPosition.fromMap(call.arguments['position'])!));
} catch (e) { } catch (e) {
print("camera#onMove error===>" + e.toString()); print("camera#onMove error===>$e");
} }
break; break;
case 'camera#onMoveEnd': case 'camera#onMoveEnd':
@ -199,7 +200,7 @@ class MethodChannelAMapFlutterMap implements AMapFlutterPlatform {
_mapEventStreamController.add(CameraPositionMoveEndEvent( _mapEventStreamController.add(CameraPositionMoveEndEvent(
mapId, CameraPosition.fromMap(call.arguments['position'])!)); mapId, CameraPosition.fromMap(call.arguments['position'])!));
} catch (e) { } catch (e) {
print("camera#onMoveEnd error===>" + e.toString()); print("camera#onMoveEnd error===>$e");
} }
break; break;
case 'map#onTap': case 'map#onTap':
@ -232,7 +233,7 @@ class MethodChannelAMapFlutterMap implements AMapFlutterPlatform {
_mapEventStreamController.add(MapPoiTouchEvent( _mapEventStreamController.add(MapPoiTouchEvent(
mapId, AMapPoi.fromJson(call.arguments['poi'])!)); mapId, AMapPoi.fromJson(call.arguments['poi'])!));
} catch (e) { } catch (e) {
print('map#onPoiTouched error===>' + e.toString()); print('map#onPoiTouched error===>$e');
} }
break; break;
} }
@ -284,4 +285,20 @@ class MethodChannelAMapFlutterMap implements AMapFlutterPlatform {
'map#fromScreenCoordinate', screenCoordinate.toJson()); 'map#fromScreenCoordinate', screenCoordinate.toJson());
return LatLng(latLng![0] as double, latLng[1] as double); return LatLng(latLng![0] as double, latLng[1] as double);
} }
Future<String> getMapContentApprovalNumber({
required int mapId,
}) async {
return await channel(mapId)
.invokeMethod<String>('map#contentApprovalNumber') ??
'';
}
Future<String> getSatelliteImageApprovalNumber({
required int mapId,
}) async {
return await channel(mapId)
.invokeMethod<String>('map#satelliteImageApprovalNumber') ??
'';
}
} }

View File

@ -1,135 +0,0 @@
import 'dart:async';
import 'package:amap_map/amap_map.dart';
import 'package:flutter/widgets.dart';
import 'package:x_amap_base/x_amap_base.dart';
/// [amap_map]插件支持默认的[InfoWindow]展示[title]和[snippet]字段,如果要自定义
/// [InfoWindow],需要集成此内置插件。
///
/// ```dart
/// AMapWidget map = AMapWidget(
/// onMapCreated: _onMapCreated,
/// markers: Set<Marker>.of(_markers.values),
/// extensions: [
/// InfoWindowExtension(
/// infoWindow: Container(
/// child: Text('Custom widget'),
/// ))
/// ],
/// )
/// ```
///
/// 此插件会在[AMapWidget]外侧套一层[Stack],根据屏幕坐标和经纬度进行适配自定义视图
///
/// ```dart
/// Stack(
/// children: [
/// child,
/// Positioned(
/// top: 0,
/// left: 0,
/// child: Visibility(child: infoWindow),
/// ),
/// ],
/// )
/// ```
class InfoWindowExtension extends AMapExtension {
InfoWindowExtension({required this.infoWindow, this.option});
final _streamController = StreamController<InfoWindowExtension>.broadcast();
final Widget infoWindow;
InfoWindowOption? option;
final GlobalKey _infoWindowKey = GlobalKey();
AMapController? mapController;
double? _x;
double? _y;
@override
void update(AMapContext aMapContext) {
_update();
}
@override
onCameraMove(CameraPosition value) {
_update();
}
_update() async {
if (mapController == null || option?.latLng == null) {
return;
}
final coordinate = await mapController!.toScreenCoordinate(option!.latLng!);
_x = coordinate.x.toDouble();
_y = coordinate.y.toDouble();
final size = _infoWindowKey.currentContext?.size;
if (size != null && _x != null && _y != null) {
_x = _x! - size.width / 2;
_y = _y! - size.height;
}
_streamController.add(this);
}
@override
bindMapController(AMapController controller) {
debugPrint('[InfoWindowExtension] bindMapController: $controller');
mapController = controller;
}
@override
Widget build(AMapContext aMapContext, Widget child) {
return Stack(
key: ValueKey(this),
children: [
child,
StreamBuilder<InfoWindowExtension>(
initialData: this,
stream: _streamController.stream,
builder: (context, snapshot) {
final data = snapshot.data;
if (data == null ||
!(data.option?.show ?? false) ||
data._x == null) {
return Container();
}
return Positioned(
top: data._y,
left: data._x,
child: Container(
key: _infoWindowKey,
margin: data.option?.offset,
child: infoWindow,
),
);
}),
],
);
}
@override
void onDispose() {
_streamController.close();
super.onDispose();
}
}
class InfoWindowOption {
bool show = false;
LatLng? latLng;
EdgeInsetsGeometry? offset;
InfoWindowOption({this.show = false, this.latLng, this.offset});
@override
String toString() {
return 'InfoWindowOption{show: $show, latLng: $latLng, offset: $offset}';
}
}

View File

@ -1 +0,0 @@
export 'buildin/info_window_extension.dart';

View File

@ -1,81 +0,0 @@
// Copyright 2023-2024 kuloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
import 'package:amap_map/amap_map.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:x_amap_base/x_amap_base.dart';
/// 插件拓展,绑定[AMapWidget]的生命周期和控制器,实现基于地图的拓展能力(通常是地图交互的可
/// 选功能)
abstract class AMapExtension {
late String _id;
String get id => _id;
AMapExtension() {
this._id = this.hashCode.toString();
}
/// 视图层级变化
/// since v1.0.4
void prepare(AMapContext aMapContext) {}
/// 视图变化
/// since v1.0.4
void update(AMapContext aMapContext) {}
void onDispose() {}
@Deprecated('使用 bindMapController 计划在1.0.6移除')
bindMethodChannel(MethodChannel channel) {}
/// 注入[AMapController] 方便地图交互
bindMapController(AMapController controller) {}
Widget build(AMapContext aMapContext, Widget child) {
/// 默认传递[AMapWidget],有部分场景需要在[AMapWidget]外包装容器,根据传递拓展列表顺序
/// 链式执行
return child;
}
/// since v1.0.4
onCameraMove(CameraPosition cameraPosition) {}
/// since v1.0.4
onCameraMoveEnd(CameraPosition cameraPosition) {}
/// since v1.0.4
onLongPress(LatLng latLng) {}
/// since v1.0.4
onPoiTouched(AMapPoi poi) {}
/// since v1.0.4
onMarkerTap(String value) {}
/// since v1.0.4
onMarkerDragEnd(String value) {}
/// since v1.0.4
onPolylineTap(String value) {}
}
Map<String, AMapExtension> keyByExtensionId(
Iterable<AMapExtension> extensions) {
// ignore: unnecessary_null_comparison
if (extensions == null) {
return <String, AMapExtension>{};
}
return Map<String, AMapExtension>.fromEntries(extensions.map(
(AMapExtension extension) =>
MapEntry<String, AMapExtension>(extension.id, extension)));
}

View File

@ -1,27 +1,42 @@
/// 地图覆盖物基类 import 'package:flutter/foundation.dart';
class BaseOverlay { class BaseOverlay {
/// overlay id /// overlay id
late String _id; String _id;
String get id => _id; String get id => _id;
BaseOverlay() { // 初始化 _id在创建对象时唯一确定
this._id = this.hashCode.toString(); BaseOverlay() : _id = _generateUniqueId();
// 设置复制的 ID确保拷贝对象时的唯一性或保留性
void setIdForCopy(String copyId) {
if (copyId.isNotEmpty) {
_id = copyId;
} else {
throw ArgumentError('Invalid ID for copy');
}
} }
void setIdForCopy(String copyId) => _id = copyId; // 克隆对象,确保子类正确实现 clone 方法
BaseOverlay clone() { BaseOverlay clone() {
throw UnimplementedError( throw UnimplementedError(
'BaseOverlay subClass should implement this methed.'); 'BaseOverlay subClass should implement this method.');
} }
// 将对象转换为 map 表示
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
throw UnimplementedError( throw UnimplementedError(
'BaseOverlay subClass should implement this methed.'); 'BaseOverlay subClass should implement this method.');
}
// 生成唯一 ID 的静态方法
static String _generateUniqueId() {
return '${DateTime.now().millisecondsSinceEpoch}_${UniqueKey()}';
} }
} }
// 序列化覆盖物集合
List<Map<String, dynamic>>? serializeOverlaySet(Set<BaseOverlay> overlays) { List<Map<String, dynamic>>? serializeOverlaySet(Set<BaseOverlay> overlays) {
return overlays return overlays
.map<Map<String, dynamic>>((BaseOverlay overlay) => overlay.toMap()) .map<Map<String, dynamic>>((BaseOverlay overlay) => overlay.toMap())

View File

@ -38,7 +38,7 @@ class CameraPosition {
/// ///
/// 主要在插件内部使用 /// 主要在插件内部使用
static CameraPosition? fromMap(dynamic json) { static CameraPosition? fromMap(dynamic json) {
if (json == null || !(json is Map<dynamic, dynamic>)) { if (json == null || json is! Map<dynamic, dynamic>) {
return null; return null;
} }
final LatLng? target = LatLng.fromJson(json['target']); final LatLng? target = LatLng.fromJson(json['target']);

View File

@ -1,31 +0,0 @@
// Copyright 2023-2024 kuloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
import 'package:amap_map/amap_map.dart';
import 'package:flutter/material.dart';
/// 上下文
class AMapContext {
final BuildContext buildContext;
final CurrentStep currentStep;
final AMapLoader loader;
AMapContext(
{required this.buildContext,
required this.currentStep,
required this.loader});
}
enum CurrentStep {
preparing,
updating,
building,
}

View File

@ -0,0 +1,37 @@
import 'package:amap_map/amap_map.dart';
import 'package:flutter/widgets.dart';
abstract class InfoWindowAdapter {
Widget? getInfoWindow(BuildContext context, Marker marker);
}
abstract class BaseInfoWindowAdapter implements InfoWindowAdapter {
final AMapController? controller;
BaseInfoWindowAdapter(this.controller);
@override
Widget? getInfoWindow(BuildContext context, Marker marker) {
final contentView = buildInfoWindowContent(context, marker);
return (contentView != null)
? FutureBuilder(
future: controller?.toScreenCoordinate(marker.position),
builder: (context, snapshot) {
if (snapshot.hasData) {
double devicePixelRatio =
MediaQuery.of(context).devicePixelRatio;
return Positioned(
left: snapshot.data!.x.toDouble() / devicePixelRatio,
top: snapshot.data!.y.toDouble() / devicePixelRatio,
child: contentView,
);
} else {
return Container(); // 当未获取到数据时,返回空的 `Container`
}
},
)
: null;
}
Widget? buildInfoWindowContent(BuildContext context, Marker marker);
}

View File

@ -8,7 +8,7 @@ import 'package:x_amap_base/x_amap_base.dart';
import 'bitmap.dart'; import 'bitmap.dart';
/// Marker拖动回调 /// Marker拖动回调
typedef void MarkerDragEndCallback(String id, LatLng endPosition); typedef MarkerDragEndCallback = void Function(String id, LatLng endPosition);
///Marker的气泡 ///Marker的气泡
/// ///
@ -91,17 +91,17 @@ class Marker extends BaseOverlay {
this.zIndex = 0.0, this.zIndex = 0.0,
this.onTap, this.onTap,
this.onDragEnd, this.onDragEnd,
}) : this.alpha = }) : alpha =
// ignore: unnecessary_null_comparison // ignore: unnecessary_null_comparison
(alpha != null ? (alpha < 0 ? 0 : (alpha > 1 ? 1 : alpha)) : alpha), (alpha != null ? (alpha < 0 ? 0 : (alpha > 1 ? 1 : alpha)) : alpha),
// ignore: unnecessary_null_comparison // ignore: unnecessary_null_comparison
this.anchor = (anchor == null anchor = (anchor == null
? Offset(0.5, 1.0) ? const Offset(0.5, 1.0)
: ((anchor.dx < 0 || : ((anchor.dx < 0 ||
anchor.dx > 1 || anchor.dx > 1 ||
anchor.dy < 0 || anchor.dy < 0 ||
anchor.dy > 1) anchor.dy > 1)
? Offset(0.5, 1.0) ? const Offset(0.5, 1.0)
: anchor)), : anchor)),
super(); super();
@ -182,6 +182,7 @@ class Marker extends BaseOverlay {
return copyMark; return copyMark;
} }
@override
Marker clone() => copyWith(); Marker clone() => copyWith();
@override @override
@ -233,9 +234,6 @@ class Marker extends BaseOverlay {
zIndex == typedOther.zIndex; zIndex == typedOther.zIndex;
} }
@override
int get hashCode => super.hashCode;
@override @override
String toString() { String toString() {
return 'Marker{id: $id, alpha: $alpha, anchor: $anchor, ' return 'Marker{id: $id, alpha: $alpha, anchor: $anchor, '
@ -243,6 +241,22 @@ class Marker extends BaseOverlay {
'icon: $icon, infoWindowEnable: $infoWindowEnable, infoWindow: $infoWindow, position: $position, rotation: $rotation, ' 'icon: $icon, infoWindowEnable: $infoWindowEnable, infoWindow: $infoWindow, position: $position, rotation: $rotation, '
'visible: $visible, zIndex: $zIndex, onTap: $onTap}'; 'visible: $visible, zIndex: $zIndex, onTap: $onTap}';
} }
@override
int get hashCode => Object.hashAll([
id,
alpha,
anchor,
clickable,
draggable,
icon,
infoWindowEnable,
infoWindow,
position,
rotation,
visible,
zIndex
]);
} }
Map<String, Marker> keyByMarkerId(Iterable<Marker> markers) { Map<String, Marker> keyByMarkerId(Iterable<Marker> markers) {

View File

@ -6,16 +6,6 @@ import 'types.dart';
class MarkerUpdates { class MarkerUpdates {
/// 根据之前的marker列表[previous]和当前的marker列表[current]创建[MakerUpdates]. /// 根据之前的marker列表[previous]和当前的marker列表[current]创建[MakerUpdates].
MarkerUpdates.from(Set<Marker> previous, Set<Marker> current) { MarkerUpdates.from(Set<Marker> previous, Set<Marker> current) {
// ignore: unnecessary_null_comparison
if (previous == null) {
previous = Set<Marker>.identity();
}
// ignore: unnecessary_null_comparison
if (current == null) {
current = Set<Marker>.identity();
}
final Map<String, Marker> previousMarkers = keyByMarkerId(previous); final Map<String, Marker> previousMarkers = keyByMarkerId(previous);
final Map<String, Marker> currentMarkers = keyByMarkerId(current); final Map<String, Marker> currentMarkers = keyByMarkerId(current);
@ -26,10 +16,10 @@ class MarkerUpdates {
return currentMarkers[id]!; return currentMarkers[id]!;
} }
final Set<String> _markerIdsToRemove = final Set<String> tempMarkerIdsToRemove =
prevMarkerIds.difference(currentMarkerIds); prevMarkerIds.difference(currentMarkerIds);
final Set<Marker> _markersToAdd = currentMarkerIds final Set<Marker> tempMarkersToAdd = currentMarkerIds
.difference(prevMarkerIds) .difference(prevMarkerIds)
.map(idToCurrentMarker) .map(idToCurrentMarker)
.toSet(); .toSet();
@ -39,15 +29,15 @@ class MarkerUpdates {
return current != previous; return current != previous;
} }
final Set<Marker> _markersToChange = currentMarkerIds final Set<Marker> tempMarkersToChange = currentMarkerIds
.intersection(prevMarkerIds) .intersection(prevMarkerIds)
.map(idToCurrentMarker) .map(idToCurrentMarker)
.where(hasChanged) .where(hasChanged)
.toSet(); .toSet();
markersToAdd = _markersToAdd; markersToAdd = tempMarkersToAdd;
markerIdsToRemove = _markerIdsToRemove; markerIdsToRemove = tempMarkerIdsToRemove;
markersToChange = _markersToChange; markersToChange = tempMarkersToChange;
} }
/// 想要添加的marker集合. /// 想要添加的marker集合.

View File

@ -18,8 +18,8 @@ class Polygon extends BaseOverlay {
this.fillColor = const Color(0xC487CEFA), this.fillColor = const Color(0xC487CEFA),
this.visible = true, this.visible = true,
this.joinType = JoinType.bevel}) this.joinType = JoinType.bevel})
: assert(points.length > 0), : assert(points.isNotEmpty),
this.strokeWidth = (strokeWidth <= 0 ? 10 : strokeWidth), strokeWidth = (strokeWidth <= 0 ? 10 : strokeWidth),
super(); super();
/// 覆盖物的坐标点数组,不能为空 /// 覆盖物的坐标点数组,不能为空
@ -60,6 +60,7 @@ class Polygon extends BaseOverlay {
return copyPolyline; return copyPolyline;
} }
@override
Polygon clone() => copyWith(); Polygon clone() => copyWith();
/// 转换成可以序列化的map /// 转换成可以序列化的map
@ -76,8 +77,8 @@ class Polygon extends BaseOverlay {
addIfPresent('id', id); addIfPresent('id', id);
json['points'] = _pointsToJson(); json['points'] = _pointsToJson();
addIfPresent('strokeWidth', strokeWidth); addIfPresent('strokeWidth', strokeWidth);
addIfPresent('strokeColor', strokeColor.value); addIfPresent('strokeColor', strokeColor.toARGB32());
addIfPresent('fillColor', fillColor.value); addIfPresent('fillColor', fillColor.toARGB32());
addIfPresent('visible', visible); addIfPresent('visible', visible);
addIfPresent('joinType', joinType.index); addIfPresent('joinType', joinType.index);
return json; return json;
@ -99,7 +100,8 @@ class Polygon extends BaseOverlay {
} }
@override @override
int get hashCode => super.hashCode; int get hashCode => Object.hashAll(
[id, points, strokeWidth, strokeColor, fillColor, visible, joinType]);
dynamic _pointsToJson() { dynamic _pointsToJson() {
final List<dynamic> result = <dynamic>[]; final List<dynamic> result = <dynamic>[];

View File

@ -9,16 +9,6 @@ import 'types.dart';
class PolygonUpdates { class PolygonUpdates {
/// 通过Polygon的前后更新集合构造一个PolygonUpdates /// 通过Polygon的前后更新集合构造一个PolygonUpdates
PolygonUpdates.from(Set<Polygon> previous, Set<Polygon> current) { PolygonUpdates.from(Set<Polygon> previous, Set<Polygon> current) {
// ignore: unnecessary_null_comparison
if (previous == null) {
previous = Set<Polygon>.identity();
}
// ignore: unnecessary_null_comparison
if (current == null) {
current = Set<Polygon>.identity();
}
final Map<String, Polygon> previousPolygons = keyByPolygonId(previous); final Map<String, Polygon> previousPolygons = keyByPolygonId(previous);
final Map<String, Polygon> currentPolygons = keyByPolygonId(current); final Map<String, Polygon> currentPolygons = keyByPolygonId(current);
@ -29,10 +19,10 @@ class PolygonUpdates {
return currentPolygons[id]!; return currentPolygons[id]!;
} }
final Set<String> _polygonIdsToRemove = final Set<String> tempPolygonIdsToRemove =
prevPolygonIds.difference(currentPolygonIds); prevPolygonIds.difference(currentPolygonIds);
final Set<Polygon> _polygonsToAdd = currentPolygonIds final Set<Polygon> tempPolygonsToAdd = currentPolygonIds
.difference(prevPolygonIds) .difference(prevPolygonIds)
.map(idToCurrentPolygon) .map(idToCurrentPolygon)
.toSet(); .toSet();
@ -42,15 +32,15 @@ class PolygonUpdates {
return current != previous; return current != previous;
} }
final Set<Polygon> _polygonsToChange = currentPolygonIds final Set<Polygon> tempPolygonsToChange = currentPolygonIds
.intersection(prevPolygonIds) .intersection(prevPolygonIds)
.map(idToCurrentPolygon) .map(idToCurrentPolygon)
.where(hasChanged) .where(hasChanged)
.toSet(); .toSet();
polygonsToAdd = _polygonsToAdd; polygonsToAdd = tempPolygonsToAdd;
polygonIdsToRemove = _polygonIdsToRemove; polygonIdsToRemove = tempPolygonIdsToRemove;
polygonsToChange = _polygonsToChange; polygonsToChange = tempPolygonsToChange;
} }
/// 想要添加的polygon对象集合. /// 想要添加的polygon对象集合.

View File

@ -62,9 +62,9 @@ class Polyline extends BaseOverlay {
this.customTexture, this.customTexture,
this.onTap, this.onTap,
this.color = const Color(0xCCC4E0F0), this.color = const Color(0xCCC4E0F0),
}) : assert(points.length > 0), }) : assert(points.isNotEmpty),
this.width = (width <= 0 ? 10 : width), width = (width <= 0 ? 10 : width),
this.alpha = (alpha < 0 ? 0 : (alpha > 1 ? 1 : alpha)), alpha = (alpha < 0 ? 0 : (alpha > 1 ? 1 : alpha)),
super(); super();
/// 覆盖物的坐标点数组,points不能为空 /// 覆盖物的坐标点数组,points不能为空
@ -131,6 +131,7 @@ class Polyline extends BaseOverlay {
return copyPolyline; return copyPolyline;
} }
@override
Polyline clone() => copyWith(); Polyline clone() => copyWith();
/// 将对象转换为可序列化的map. /// 将对象转换为可序列化的map.
@ -154,7 +155,7 @@ class Polyline extends BaseOverlay {
addIfPresent('capType', capType.index); addIfPresent('capType', capType.index);
addIfPresent('joinType', joinType.index); addIfPresent('joinType', joinType.index);
addIfPresent('customTexture', customTexture?.toMap()); addIfPresent('customTexture', customTexture?.toMap());
addIfPresent('color', color.value); addIfPresent('color', color.toARGB32());
return json; return json;
} }
@ -176,9 +177,6 @@ class Polyline extends BaseOverlay {
color == typedOther.color; color == typedOther.color;
} }
@override
int get hashCode => super.hashCode;
dynamic _pointsToJson() { dynamic _pointsToJson() {
final List<dynamic> result = <dynamic>[]; final List<dynamic> result = <dynamic>[];
for (final LatLng point in points) { for (final LatLng point in points) {
@ -186,6 +184,20 @@ class Polyline extends BaseOverlay {
} }
return result; return result;
} }
@override
int get hashCode => Object.hashAll([
id,
points,
width,
visible,
geodesic,
alpha,
dashLineType,
capType,
joinType,
color
]);
} }
Map<String, Polyline> keyByPolylineId(Iterable<Polyline> polylines) { Map<String, Polyline> keyByPolylineId(Iterable<Polyline> polylines) {

View File

@ -10,16 +10,6 @@ import 'types.dart';
class PolylineUpdates { class PolylineUpdates {
/// 通过polyline的前后更新集合构造一个polylineUpdates /// 通过polyline的前后更新集合构造一个polylineUpdates
PolylineUpdates.from(Set<Polyline> previous, Set<Polyline> current) { PolylineUpdates.from(Set<Polyline> previous, Set<Polyline> current) {
// ignore: unnecessary_null_comparison
if (previous == null) {
previous = Set<Polyline>.identity();
}
// ignore: unnecessary_null_comparison
if (current == null) {
current = Set<Polyline>.identity();
}
final Map<String, Polyline> previousPolylines = keyByPolylineId(previous); final Map<String, Polyline> previousPolylines = keyByPolylineId(previous);
final Map<String, Polyline> currentPolylines = keyByPolylineId(current); final Map<String, Polyline> currentPolylines = keyByPolylineId(current);
@ -30,10 +20,10 @@ class PolylineUpdates {
return currentPolylines[id]!; return currentPolylines[id]!;
} }
final Set<String> _polylineIdsToRemove = final Set<String> tempPolylineIdsToRemove =
prevPolylineIds.difference(currentPolylineIds); prevPolylineIds.difference(currentPolylineIds);
final Set<Polyline> _polylinesToAdd = currentPolylineIds final Set<Polyline> tempPolylinesToAdd = currentPolylineIds
.difference(prevPolylineIds) .difference(prevPolylineIds)
.map(idToCurrentPolyline) .map(idToCurrentPolyline)
.toSet(); .toSet();
@ -43,15 +33,15 @@ class PolylineUpdates {
return current != previous; return current != previous;
} }
final Set<Polyline> _polylinesToChange = currentPolylineIds final Set<Polyline> tempPolylinesToChange = currentPolylineIds
.intersection(prevPolylineIds) .intersection(prevPolylineIds)
.map(idToCurrentPolyline) .map(idToCurrentPolyline)
.where(hasChanged) .where(hasChanged)
.toSet(); .toSet();
polylinesToAdd = _polylinesToAdd; polylinesToAdd = tempPolylinesToAdd;
polylineIdsToRemove = _polylineIdsToRemove; polylineIdsToRemove = tempPolylineIdsToRemove;
polylinesToChange = _polylinesToChange; polylinesToChange = tempPolylinesToChange;
} }
/// 用于添加polyline的集合 /// 用于添加polyline的集合

View File

@ -20,8 +20,5 @@ export 'polyline_updates.dart';
export 'polygon.dart'; export 'polygon.dart';
export 'polygon_updates.dart'; export 'polygon_updates.dart';
export 'bitmap.dart'; export 'bitmap.dart';
export 'extension_context.dart';
export 'amap_extension.dart';
export 'screen_coordinate.dart'; export 'screen_coordinate.dart';
export 'info_window_adapter.dart';
export '../extension/extensions.dart';

View File

@ -21,6 +21,15 @@ enum MapType {
bus, bus,
} }
/// 地图底图语言,目前支持中文底图和英文底图
enum MapLanguage {
chinese('zh_cn'),
english('en');
final String value;
const MapLanguage(this.value);
}
// 设置摄像机的边界. // 设置摄像机的边界.
class CameraTargetBounds { class CameraTargetBounds {
/// 使用指定的边界框或空值创建摄影机目标边界 /// 使用指定的边界框或空值创建摄影机目标边界
@ -63,12 +72,10 @@ class MinMaxZoomPreference {
/// 缩放级别范围为[3, 20],超出范围取边界值 /// 缩放级别范围为[3, 20],超出范围取边界值
/// ///
const MinMaxZoomPreference(double minZoom, double maxZoom) const MinMaxZoomPreference(double minZoom, double maxZoom)
: this.minZoom = : minZoom = ((minZoom < 3 ? 3 : minZoom) > (maxZoom > 20 ? 20 : maxZoom)
((minZoom < 3 ? 3 : minZoom) > (maxZoom > 20 ? 20 : maxZoom)
? maxZoom ? maxZoom
: minZoom), : minZoom),
this.maxZoom = maxZoom = ((minZoom < 3 ? 3 : minZoom) > (maxZoom > 20 ? 20 : maxZoom)
((minZoom < 3 ? 3 : minZoom) > (maxZoom > 20 ? 20 : maxZoom)
? minZoom ? minZoom
: maxZoom); : maxZoom);
@ -143,10 +150,10 @@ class MyLocationStyleOptions {
} }
return MyLocationStyleOptions( return MyLocationStyleOptions(
json['enabled'] ?? false, json['enabled'] ?? false,
circleFillColor: json['circleFillColor'] ?? null, circleFillColor: json['circleFillColor'],
circleStrokeColor: json['circleStrokeColor'] ?? null, circleStrokeColor: json['circleStrokeColor'],
circleStrokeWidth: json['circleStrokeWidth'] ?? null, circleStrokeWidth: json['circleStrokeWidth'],
icon: json['icon'] ?? null, icon: json['icon'],
); );
} }
@ -160,8 +167,8 @@ class MyLocationStyleOptions {
} }
addIfPresent('enabled', enabled); addIfPresent('enabled', enabled);
addIfPresent('circleFillColor', circleFillColor?.value); addIfPresent('circleFillColor', circleFillColor?.toARGB32());
addIfPresent('circleStrokeColor', circleStrokeColor?.value); addIfPresent('circleStrokeColor', circleStrokeColor?.toARGB32());
addIfPresent('circleStrokeWidth', circleStrokeWidth); addIfPresent('circleStrokeWidth', circleStrokeWidth);
addIfPresent('icon', icon?.toMap()); addIfPresent('icon', icon?.toMap());
return json; return json;
@ -216,8 +223,8 @@ class CustomStyleOptions {
} }
return CustomStyleOptions( return CustomStyleOptions(
json['enabled'] ?? false, json['enabled'] ?? false,
styleData: json['styleData'] ?? null, styleData: json['styleData'],
styleExtraData: json['styleExtraData'] ?? null, styleExtraData: json['styleExtraData'],
); );
} }

View File

@ -1,4 +1,4 @@
part of amap_map; part of '../../amap_map.dart';
bool isLocationValid(AMapLocation location) { bool isLocationValid(AMapLocation location) {
final LatLng latLng = location.latLng; final LatLng latLng = location.latLng;

View File

@ -1,6 +1,6 @@
name: amap_map name: amap_map
description: Amap SDK Flutter plugin for integrating AMapSDK in iOS and Android applications. description: Amap SDK Flutter plugin for integrating AMapSDK in iOS and Android applications.
version: 1.0.8 version: 1.0.15
homepage: https://github.com/kuloud/amap_map homepage: https://github.com/kuloud/amap_map
issue_tracker: https://github.com/kuloud/amap_map/issues issue_tracker: https://github.com/kuloud/amap_map/issues
platforms: platforms:
@ -18,17 +18,15 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
flutter_plugin_android_lifecycle: ^2.0.17 flutter_plugin_android_lifecycle: ^2.0.21
plugin_platform_interface: ^2.1.8 plugin_platform_interface: ^2.1.8
stream_transform: ^2.0.0 stream_transform: ^2.0.0
x_amap_base: ^1.0.3 x_amap_base: ^1.0.3
x_common: ^1.0.4 x_common: ^1.0.4
# provider: ^6.1.1
# x_amap_base:
# path: ../x_amap_base
dev_dependencies: dev_dependencies:
flutter_lints: ^5.0.0
flutter_test: flutter_test:
sdk: flutter sdk: flutter