init project
This commit is contained in:
19
ios/Classes/AMapFlutterFactory.h
Normal file
19
ios/Classes/AMapFlutterFactory.h
Normal file
@ -0,0 +1,19 @@
|
||||
//
|
||||
// AMapFlutterFactory.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/10/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AMapFlutterFactory : NSObject<FlutterPlatformViewFactory>
|
||||
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
36
ios/Classes/AMapFlutterFactory.m
Normal file
36
ios/Classes/AMapFlutterFactory.m
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// AMapFlutterFactory.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/10/29.
|
||||
//
|
||||
|
||||
#import "AMapFlutterFactory.h"
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
#import "AMapViewController.h"
|
||||
|
||||
@implementation AMapFlutterFactory {
|
||||
NSObject<FlutterPluginRegistrar>* _registrar;
|
||||
}
|
||||
|
||||
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_registrar = registrar;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSObject<FlutterMessageCodec>*)createArgsCodec {
|
||||
return [FlutterStandardMessageCodec sharedInstance];
|
||||
}
|
||||
|
||||
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args {
|
||||
return [[AMapViewController alloc] initWithFrame:frame
|
||||
viewIdentifier:viewId
|
||||
arguments:args
|
||||
registrar:_registrar];
|
||||
}
|
||||
@end
|
5
ios/Classes/AMapFlutterMapPlugin.h
Normal file
5
ios/Classes/AMapFlutterMapPlugin.h
Normal file
@ -0,0 +1,5 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
@interface AMapFlutterMapPlugin : NSObject<FlutterPlugin>
|
||||
@end
|
18
ios/Classes/AMapFlutterMapPlugin.m
Normal file
18
ios/Classes/AMapFlutterMapPlugin.m
Normal file
@ -0,0 +1,18 @@
|
||||
#import "AMapFlutterMapPlugin.h"
|
||||
#import "AMapFlutterFactory.h"
|
||||
|
||||
@implementation AMapFlutterMapPlugin{
|
||||
NSObject<FlutterPluginRegistrar>* _registrar;
|
||||
FlutterMethodChannel* _channel;
|
||||
NSMutableDictionary* _mapControllers;
|
||||
}
|
||||
|
||||
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
AMapFlutterFactory* aMapFactory = [[AMapFlutterFactory alloc] initWithRegistrar:registrar];
|
||||
[registrar registerViewFactory:aMapFactory
|
||||
withId:@"com.amap.flutter.map"
|
||||
gestureRecognizersBlockingPolicy:
|
||||
FlutterPlatformViewGestureRecognizersBlockingPolicyWaitUntilTouchesEnded];
|
||||
}
|
||||
|
||||
@end
|
23
ios/Classes/AMapViewController.h
Normal file
23
ios/Classes/AMapViewController.h
Normal file
@ -0,0 +1,23 @@
|
||||
//
|
||||
// AMapViewController.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/10/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Flutter/Flutter.h>
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AMapViewController : NSObject<FlutterPlatformView>
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args
|
||||
registrar:(NSObject<FlutterPluginRegistrar>*)registrar;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
499
ios/Classes/AMapViewController.m
Normal file
499
ios/Classes/AMapViewController.m
Normal file
@ -0,0 +1,499 @@
|
||||
//
|
||||
// AMapViewController.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/10/29.
|
||||
//
|
||||
|
||||
#import "AMapViewController.h"
|
||||
#import "AMapJsonUtils.h"
|
||||
#import "AMapCameraPosition.h"
|
||||
#import "MAMapView+Flutter.h"
|
||||
#import "MAAnnotationView+Flutter.h"
|
||||
#import "AMapMarkerController.h"
|
||||
#import "MAPointAnnotation+Flutter.h"
|
||||
#import "AMapPolylineController.h"
|
||||
#import "MAPolyline+Flutter.h"
|
||||
#import "AMapPolyline.h"
|
||||
#import "MAPolylineRenderer+Flutter.h"
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import "AMapPolygonController.h"
|
||||
#import "MAPolygon+Flutter.h"
|
||||
#import "MAPolygonRenderer+Flutter.h"
|
||||
#import "AMapPolygon.h"
|
||||
#import <AMapFoundationKit/AMapFoundationKit.h>
|
||||
#import "AMapLocation.h"
|
||||
#import "AMapJsonUtils.h"
|
||||
#import "AMapConvertUtil.h"
|
||||
#import "FlutterMethodChannel+MethodCallDispatch.h"
|
||||
|
||||
@interface AMapViewController ()<MAMapViewDelegate>
|
||||
|
||||
@property (nonatomic,strong) MAMapView *mapView;
|
||||
@property (nonatomic,strong) FlutterMethodChannel *channel;
|
||||
@property (nonatomic,assign) int64_t viewId;
|
||||
@property (nonatomic,strong) NSObject<FlutterPluginRegistrar>* registrar;
|
||||
|
||||
@property (nonatomic,strong) AMapMarkerController *markerController;
|
||||
@property (nonatomic,strong) AMapPolylineController *polylinesController;
|
||||
@property (nonatomic,strong) AMapPolygonController *polygonsController;
|
||||
|
||||
@property (nonatomic,copy) FlutterResult waitForMapCallBack;//waitForMap的回调,仅当地图没有加载完成时缓存使用
|
||||
@property (nonatomic,assign) BOOL mapInitCompleted;//地图初始化完成,首帧回调的标记
|
||||
|
||||
@property (nonatomic,assign) MAMapRect initLimitMapRect;//初始化时,限制的地图范围;如果为{0,0,0,0},则没有限制
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation AMapViewController
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args
|
||||
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
if (self = [super init]) {
|
||||
NSAssert([args isKindOfClass:[NSDictionary class]], @"传参错误");
|
||||
//构建methedChannel
|
||||
NSString* channelName =
|
||||
[NSString stringWithFormat:@"amap_map_%lld", viewId];
|
||||
_channel = [FlutterMethodChannel methodChannelWithName:channelName
|
||||
binaryMessenger:registrar.messenger];
|
||||
|
||||
NSDictionary *dict = args;
|
||||
|
||||
NSDictionary *apiKey = dict[@"apiKey"];
|
||||
if (apiKey && [apiKey isKindOfClass:[NSDictionary class]]) {
|
||||
NSString *iosKey = apiKey[@"iosKey"];
|
||||
if (iosKey && iosKey.length > 0) {//通过flutter传入key,则再重新设置一次key
|
||||
[AMapServices sharedServices].apiKey = iosKey;
|
||||
}
|
||||
}
|
||||
//这里统一检查key的设置是否生效
|
||||
NSAssert(([AMapServices sharedServices].apiKey != nil), @"没有设置APIKey,请先设置key");
|
||||
|
||||
NSDictionary *cameraDict = [dict objectForKey:@"initialCameraPosition"];
|
||||
AMapCameraPosition *cameraPosition = [AMapJsonUtils modelFromDict:cameraDict modelClass:[AMapCameraPosition class]];
|
||||
|
||||
_viewId = viewId;
|
||||
|
||||
if ([dict objectForKey:@"privacyStatement"] != nil) {
|
||||
[self updatePrivacyStateWithDict:[dict objectForKey:@"privacyStatement"]];
|
||||
}
|
||||
|
||||
|
||||
self.mapInitCompleted = NO;
|
||||
_mapView = [[MAMapView alloc] initWithFrame:frame];
|
||||
if (_mapView == nil && (MAMapVersionNumber) >= 80100) {
|
||||
NSAssert(_mapView,@"MAMapView初始化失败,地图SDK8.1.0及以上,请务必确保调用SDK任何接口前先调用更新隐私合规updatePrivacyShow:privacyInfo、updatePrivacyAgree两个接口");
|
||||
}
|
||||
_mapView.delegate = self;
|
||||
_mapView.accessibilityElementsHidden = NO;
|
||||
[_mapView setCameraPosition:cameraPosition animated:NO duration:0];
|
||||
_registrar = registrar;
|
||||
[self.mapView updateMapViewOption:[dict objectForKey:@"options"] withRegistrar:_registrar];
|
||||
self.initLimitMapRect = [self getLimitMapRectFromOption:[dict objectForKey:@"options"]];
|
||||
if (MAMapRectIsEmpty(self.initLimitMapRect) == NO) {//限制了显示区域,则添加KVO监听
|
||||
[_mapView addObserver:self forKeyPath:@"frame" options:0 context:nil];
|
||||
}
|
||||
|
||||
_markerController = [[AMapMarkerController alloc] init:_channel
|
||||
mapView:_mapView
|
||||
registrar:registrar];
|
||||
_polylinesController = [[AMapPolylineController alloc] init:_channel
|
||||
mapView:_mapView
|
||||
registrar:registrar];
|
||||
_polygonsController = [[AMapPolygonController alloc] init:_channel
|
||||
mapView:_mapView
|
||||
registrar:registrar];
|
||||
id markersToAdd = args[@"markersToAdd"];
|
||||
if ([markersToAdd isKindOfClass:[NSArray class]]) {
|
||||
[_markerController addMarkers:markersToAdd];
|
||||
}
|
||||
id polylinesToAdd = args[@"polylinesToAdd"];
|
||||
if ([polylinesToAdd isKindOfClass:[NSArray class]]) {
|
||||
[_polylinesController addPolylines:polylinesToAdd];
|
||||
}
|
||||
id polygonsToAdd = args[@"polygonsToAdd"];
|
||||
if ([polygonsToAdd isKindOfClass:[NSArray class]]) {
|
||||
[_polygonsController addPolygons:polygonsToAdd];
|
||||
}
|
||||
|
||||
[self setMethodCallHandler];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIView*)view {
|
||||
return _mapView;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (MAMapRectIsEmpty(_initLimitMapRect) == NO) {//避免没有开始渲染,frame监听还存在时,快速销毁
|
||||
[_mapView removeObserver:self forKeyPath:@"frame"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updatePrivacyStateWithDict:(NSDictionary *)dict {
|
||||
if ((MAMapVersionNumber) < 80100) {
|
||||
NSLog(@"当前地图SDK版本没有隐私合规接口,请升级地图SDK到8.1.0及以上版本");
|
||||
return;
|
||||
}
|
||||
if (dict == nil || [dict isKindOfClass:[NSDictionary class]] == NO) {
|
||||
return;
|
||||
}
|
||||
if (dict[@"hasContains"] != nil && dict[@"hasShow"] != nil) {
|
||||
[MAMapView updatePrivacyShow:[dict[@"hasShow"] integerValue] privacyInfo:[dict[@"hasContains"] integerValue]];
|
||||
}
|
||||
if (dict[@"hasAgree"] != nil) {
|
||||
[MAMapView updatePrivacyAgree:[dict[@"hasAgree"] integerValue]];
|
||||
}
|
||||
}
|
||||
|
||||
- (MAMapRect)getLimitMapRectFromOption:(NSDictionary *)dict {
|
||||
NSArray *limitBounds = dict[@"limitBounds"];
|
||||
if (limitBounds) {
|
||||
return [AMapConvertUtil mapRectFromArray:limitBounds];
|
||||
} else {
|
||||
return MAMapRectMake(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString*)keyPath
|
||||
ofObject:(id)object
|
||||
change:(NSDictionary*)change
|
||||
context:(void*)context {
|
||||
if (MAMapRectIsEmpty(self.initLimitMapRect) == YES ) {//初始化时,没有设置显示范围,则不再监听frame的变化
|
||||
[_mapView removeObserver:self forKeyPath:@"frame"];
|
||||
return;
|
||||
}
|
||||
if (object == _mapView && [keyPath isEqualToString:@"frame"]) {
|
||||
CGRect bounds = _mapView.bounds;
|
||||
if (CGRectEqualToRect(bounds, CGRectZero)) {
|
||||
// 忽略初始化时,frame为0的情况,仅当frame更新为非0时,才设置limitRect
|
||||
return;
|
||||
}
|
||||
//监听到一次,就直接移除KVO
|
||||
[_mapView removeObserver:self forKeyPath:@"frame"];
|
||||
if (MAMapRectIsEmpty(self.initLimitMapRect) == NO) {
|
||||
//加0.1s的延迟,确保地图的frame和内部引擎都已经更新
|
||||
MAMapRect tempLimitMapRect = self.initLimitMapRect;
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
self.mapView.limitMapRect = tempLimitMapRect;
|
||||
});
|
||||
//避免KVO短时间触发多次,造成多次延迟派发
|
||||
self.initLimitMapRect = MAMapRectMake(0, 0, 0, 0);
|
||||
}
|
||||
} else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)setMethodCallHandler {
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
[self.channel addMethodName:@"map#update" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
[weakSelf.mapView updateMapViewOption:call.arguments[@"options"] withRegistrar:weakSelf.registrar];
|
||||
result(nil);
|
||||
}];
|
||||
[self.channel addMethodName:@"map#waitForMap" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
if (weakSelf.mapInitCompleted) {
|
||||
result(nil);
|
||||
} else {
|
||||
weakSelf.waitForMapCallBack = result;
|
||||
}
|
||||
}];
|
||||
[self.channel addMethodName:@"camera#move" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
[weakSelf.mapView setCameraUpdateDict:call.arguments];
|
||||
result(nil);
|
||||
}];
|
||||
[self.channel addMethodName:@"map#takeSnapshot" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
[weakSelf.mapView takeSnapshotInRect:weakSelf.mapView.frame withCompletionBlock:^(UIImage *resultImage, NSInteger state) {
|
||||
if (state == 1 && resultImage) {
|
||||
NSData *data = UIImagePNGRepresentation(resultImage);
|
||||
result([FlutterStandardTypedData typedDataWithBytes:data]);
|
||||
} else if (state == 0) {
|
||||
NSLog(@"takeSnapsShot 载入不完整");
|
||||
}
|
||||
}];
|
||||
}];
|
||||
[self.channel addMethodName:@"map#setRenderFps" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
NSInteger fps = [call.arguments[@"fps"] integerValue];
|
||||
[weakSelf.mapView setMaxRenderFrame:fps];
|
||||
result(nil);
|
||||
}];
|
||||
[self.channel addMethodName:@"map#contentApprovalNumber" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
NSString *approvalNumber = [weakSelf.mapView mapContentApprovalNumber];
|
||||
result(approvalNumber);
|
||||
}];
|
||||
[self.channel addMethodName:@"map#satelliteImageApprovalNumber" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
NSString *sateApprovalNumber = [weakSelf.mapView satelliteImageApprovalNumber];
|
||||
result(sateApprovalNumber);
|
||||
}];
|
||||
[self.channel addMethodName:@"map#clearDisk" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
[weakSelf.mapView clearDisk];
|
||||
result(nil);
|
||||
}];
|
||||
}
|
||||
|
||||
//MARK: MAMapViewDelegate
|
||||
|
||||
//MARK: 定位相关回调
|
||||
|
||||
- (void)mapView:(MAMapView *)mapView didChangeUserTrackingMode:(MAUserTrackingMode)mode animated:(BOOL)animated {
|
||||
NSLog(@"%s,mapView:%@ mode:%ld",__func__,mapView,(long)mode);
|
||||
}
|
||||
/**
|
||||
* @brief 在地图View将要启动定位时,会调用此函数
|
||||
* @param mapView 地图View
|
||||
*/
|
||||
- (void)mapViewWillStartLocatingUser:(MAMapView *)mapView {
|
||||
NSLog(@"%s,mapView:%@",__func__,mapView);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在地图View停止定位后,会调用此函数
|
||||
* @param mapView 地图View
|
||||
*/
|
||||
- (void)mapViewDidStopLocatingUser:(MAMapView *)mapView {
|
||||
NSLog(@"%s,mapView:%@",__func__,mapView);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 位置或者设备方向更新后,会调用此函数
|
||||
* @param mapView 地图View
|
||||
* @param userLocation 用户定位信息(包括位置与设备方向等数据)
|
||||
* @param updatingLocation 标示是否是location数据更新, YES:location数据更新 NO:heading数据更新
|
||||
*/
|
||||
- (void)mapView:(MAMapView *)mapView didUpdateUserLocation:(MAUserLocation *)userLocation updatingLocation:(BOOL)updatingLocation {
|
||||
if (updatingLocation && userLocation.location) {
|
||||
AMapLocation *location = [[AMapLocation alloc] init];
|
||||
[location updateWithUserLocation:userLocation.location];
|
||||
NSDictionary *jsonObjc = [AMapJsonUtils jsonObjectFromModel:location];
|
||||
NSArray *latlng = [AMapConvertUtil jsonArrayFromCoordinate:location.latLng];
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:jsonObjc];
|
||||
[dict setValue:latlng forKey:@"latLng"];
|
||||
[_channel invokeMethod:@"location#changed" arguments:@{@"location" : dict}];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 当plist配置NSLocationAlwaysUsageDescription或者NSLocationAlwaysAndWhenInUseUsageDescription,并且[CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined,会调用代理的此方法。
|
||||
此方法实现调用后台权限API即可( 该回调必须实现 [locationManager requestAlwaysAuthorization] ); since 6.8.0
|
||||
* @param locationManager 地图的CLLocationManager。
|
||||
*/
|
||||
- (void)mapViewRequireLocationAuth:(CLLocationManager *)locationManager {
|
||||
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
|
||||
[locationManager requestAlwaysAuthorization];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 定位失败后,会调用此函数
|
||||
* @param mapView 地图View
|
||||
* @param error 错误号,参考CLError.h中定义的错误号
|
||||
*/
|
||||
- (void)mapView:(MAMapView *)mapView didFailToLocateUserWithError:(NSError *)error {
|
||||
NSLog(@"%s,mapView:%@ error:%@",__func__,mapView,error);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 地图加载成功
|
||||
* @param mapView 地图View
|
||||
*/
|
||||
- (void)mapViewDidFinishLoadingMap:(MAMapView *)mapView {
|
||||
NSLog(@"%s,mapView:%@",__func__,mapView);
|
||||
}
|
||||
|
||||
- (void)mapInitComplete:(MAMapView *)mapView {
|
||||
NSLog(@"%s,mapView:%@",__func__,mapView);
|
||||
self.mapInitCompleted = YES;
|
||||
if (self.waitForMapCallBack) {
|
||||
self.waitForMapCallBack(nil);
|
||||
self.waitForMapCallBack = nil;
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: Annotation相关回调
|
||||
|
||||
- (MAAnnotationView *)mapView:(MAMapView *)mapView viewForAnnotation:(id<MAAnnotation>)annotation {
|
||||
if ([annotation isKindOfClass:[MAPointAnnotation class]] == NO) {
|
||||
return nil;
|
||||
}
|
||||
MAPointAnnotation *fAnno = annotation;
|
||||
if (fAnno.markerId == nil) {
|
||||
return nil;
|
||||
}
|
||||
AMapMarker *marker = [_markerController markerForId:fAnno.markerId];
|
||||
// TODO: 这里只实现基础AnnotationView,不再根据marker的数据差异,区分是annotationView还是pinAnnotationView了;
|
||||
MAAnnotationView *view = [mapView dequeueReusableAnnotationViewWithIdentifier:AMapFlutterAnnotationViewIdentifier];
|
||||
if (view == nil) {
|
||||
view = [[MAAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:AMapFlutterAnnotationViewIdentifier];
|
||||
}
|
||||
[view updateViewWithMarker:marker];
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 当mapView新添加annotation views时,调用此接口
|
||||
* @param mapView 地图View
|
||||
* @param views 新添加的annotation views
|
||||
*/
|
||||
- (void)mapView:(MAMapView *)mapView didAddAnnotationViews:(NSArray *)views {
|
||||
for (MAAnnotationView *view in views) {
|
||||
if ([view.annotation isKindOfClass:[MAAnnotationView class]] == NO) {
|
||||
return;
|
||||
}
|
||||
MAPointAnnotation *fAnno = view.annotation;
|
||||
if (fAnno.markerId == nil) {
|
||||
return;
|
||||
}
|
||||
AMapMarker *marker = [_markerController markerForId:fAnno.markerId];
|
||||
[view updateViewWithMarker:marker];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 标注view的calloutview整体点击时,触发该回调。只有使用默认calloutview时才生效。
|
||||
* @param mapView 地图的view
|
||||
* @param view calloutView所属的annotationView
|
||||
*/
|
||||
//- (void)mapView:(MAMapView *)mapView didAnnotationViewCalloutTapped:(MAAnnotationView *)view {
|
||||
// MAPointAnnotation *fAnno = view.annotation;
|
||||
// if (fAnno.markerId == nil) {
|
||||
// return;
|
||||
// }
|
||||
// [_markerController onInfoWindowTap:fAnno.markerId];
|
||||
//}
|
||||
|
||||
/**
|
||||
* @brief 标注view被点击时,触发该回调。(since 5.7.0)
|
||||
* @param mapView 地图的view
|
||||
* @param view annotationView
|
||||
*/
|
||||
- (void)mapView:(MAMapView *)mapView didAnnotationViewTapped:(MAAnnotationView *)view {
|
||||
MAPointAnnotation *fAnno = view.annotation;
|
||||
if (fAnno.markerId == nil) {
|
||||
return;
|
||||
}
|
||||
[_markerController onMarkerTap:fAnno.markerId];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 拖动annotation view时view的状态变化
|
||||
* @param mapView 地图View
|
||||
* @param view annotation view
|
||||
* @param newState 新状态
|
||||
* @param oldState 旧状态
|
||||
*/
|
||||
- (void)mapView:(MAMapView *)mapView annotationView:(MAAnnotationView *)view didChangeDragState:(MAAnnotationViewDragState)newState
|
||||
fromOldState:(MAAnnotationViewDragState)oldState {
|
||||
if (newState == MAAnnotationViewDragStateEnding) {
|
||||
MAPointAnnotation *fAnno = view.annotation;
|
||||
if (fAnno.markerId == nil) {
|
||||
return;
|
||||
}
|
||||
[_markerController onMarker:fAnno.markerId endPostion:fAnno.coordinate];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据overlay生成对应的Renderer
|
||||
* @param mapView 地图View
|
||||
* @param overlay 指定的overlay
|
||||
* @return 生成的覆盖物Renderer
|
||||
*/
|
||||
- (MAOverlayRenderer *)mapView:(MAMapView *)mapView rendererForOverlay:(id <MAOverlay>)overlay {
|
||||
if ([overlay isKindOfClass:[MAPolyline class]]) {
|
||||
MAPolyline *polyline = overlay;
|
||||
if (polyline.polylineId == nil) {
|
||||
return nil;
|
||||
}
|
||||
AMapPolyline *fPolyline = [_polylinesController polylineForId:polyline.polylineId];
|
||||
MAPolylineRenderer *polylineRenderer = [[MAPolylineRenderer alloc] initWithPolyline:overlay];
|
||||
[polylineRenderer updateRenderWithPolyline:fPolyline];
|
||||
return polylineRenderer;
|
||||
} else if ([overlay isKindOfClass:[MAPolygon class]]) {
|
||||
MAPolygon *polygon = overlay;
|
||||
if (polygon.polygonId == nil) {
|
||||
return nil;
|
||||
}
|
||||
AMapPolygon *fPolygon = [_polygonsController polygonForId:polygon.polygonId];
|
||||
MAPolygonRenderer *polygonRenderer = [[MAPolygonRenderer alloc] initWithPolygon:polygon];
|
||||
[polygonRenderer updateRenderWithPolygon:fPolygon];
|
||||
return polygonRenderer;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 单击地图回调,返回经纬度
|
||||
* @param mapView 地图View
|
||||
* @param coordinate 经纬度
|
||||
*/
|
||||
- (void)mapView:(MAMapView *)mapView didSingleTappedAtCoordinate:(CLLocationCoordinate2D)coordinate {
|
||||
NSArray *latLng = [AMapConvertUtil jsonArrayFromCoordinate:coordinate];
|
||||
[_channel invokeMethod:@"map#onTap" arguments:@{@"latLng":latLng}];
|
||||
NSArray *polylineRenderArray = [mapView getHittedPolylinesWith:coordinate traverseAll:NO];
|
||||
if (polylineRenderArray && polylineRenderArray.count > 0) {
|
||||
MAOverlayRenderer *render = polylineRenderArray.firstObject;
|
||||
MAPolyline *polyline = render.overlay;
|
||||
if (polyline.polylineId) {
|
||||
[_polylinesController onPolylineTap:polyline.polylineId];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 长按地图,返回经纬度
|
||||
* @param mapView 地图View
|
||||
* @param coordinate 经纬度
|
||||
*/
|
||||
- (void)mapView:(MAMapView *)mapView didLongPressedAtCoordinate:(CLLocationCoordinate2D)coordinate {
|
||||
NSArray *latLng = [AMapConvertUtil jsonArrayFromCoordinate:coordinate];
|
||||
[_channel invokeMethod:@"map#onLongPress" arguments:@{@"latLng":latLng}];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 当touchPOIEnabled == YES时,单击地图使用该回调获取POI信息
|
||||
* @param mapView 地图View
|
||||
* @param pois 获取到的poi数组(由MATouchPoi组成)
|
||||
*/
|
||||
- (void)mapView:(MAMapView *)mapView didTouchPois:(NSArray *)pois {
|
||||
MATouchPoi *poi = pois.firstObject;
|
||||
NSDictionary *dict = [AMapConvertUtil dictFromTouchPOI:poi];
|
||||
if (dict) {
|
||||
[_channel invokeMethod:@"map#onPoiTouched" arguments:@{@"poi":dict}];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 地图区域改变过程中会调用此接口 since 4.6.0
|
||||
* @param mapView 地图View
|
||||
*/
|
||||
- (void)mapViewRegionChanged:(MAMapView *)mapView {
|
||||
// TODO: 这里消息回调太多,channel可能有性能影响
|
||||
AMapCameraPosition *cameraPos = [mapView getCurrentCameraPosition];
|
||||
NSDictionary *dict = [cameraPos toDictionary];
|
||||
if (dict) {
|
||||
[_channel invokeMethod:@"camera#onMove" arguments:@{@"position":dict}];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 地图区域改变完成后会调用此接口
|
||||
* @param mapView 地图View
|
||||
* @param animated 是否动画
|
||||
*/
|
||||
- (void)mapView:(MAMapView *)mapView regionDidChangeAnimated:(BOOL)animated {
|
||||
AMapCameraPosition *cameraPos = [mapView getCurrentCameraPosition];
|
||||
NSDictionary *dict = [cameraPos toDictionary];
|
||||
if (dict) {
|
||||
[_channel invokeMethod:@"camera#onMoveEnd" arguments:@{@"position":dict}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@ -0,0 +1,32 @@
|
||||
//
|
||||
// FlutterMethodChannel+MethodCallDispatch.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/16.
|
||||
//
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
#import "AMapMethodCallDispatcher.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface FlutterMethodChannel (MethodCallDispatch)
|
||||
|
||||
@property (nonatomic,strong,readonly) AMapMethodCallDispatcher* methodCallDispatcher;
|
||||
|
||||
|
||||
/// 添加methodCall的回调(注意:使用该方法之后,就不能再调用setMethodCallHandler: 方法了)
|
||||
/// @param methodName methodName对应call的唯一方法名
|
||||
/// @param handler 回调处理
|
||||
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler;
|
||||
|
||||
/// 移除methodCall对应的回调
|
||||
/// @param methodName 唯一的方法名
|
||||
- (void)removeHandlerWithMethodName:(NSString *)methodName;
|
||||
|
||||
/// 清空所有的handler
|
||||
- (void)clearAllHandler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
@ -0,0 +1,42 @@
|
||||
//
|
||||
// FlutterMethodChannel+MethodCallDispatch.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/16.
|
||||
//
|
||||
|
||||
#import "FlutterMethodChannel+MethodCallDispatch.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation FlutterMethodChannel (MethodCallDispatch)
|
||||
|
||||
- (AMapMethodCallDispatcher *)methodCallDispatcher {
|
||||
return objc_getAssociatedObject(self, @selector(methodCallDispatcher));
|
||||
}
|
||||
|
||||
- (void)setMethodCallDispatcher:(AMapMethodCallDispatcher *)dispatcher {
|
||||
objc_setAssociatedObject(self, @selector(methodCallDispatcher), dispatcher, OBJC_ASSOCIATION_RETAIN);
|
||||
}
|
||||
|
||||
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler {
|
||||
if (self.methodCallDispatcher == nil) {
|
||||
self.methodCallDispatcher = [[AMapMethodCallDispatcher alloc] init];
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[self setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
if (weakSelf.methodCallDispatcher) {
|
||||
[weakSelf.methodCallDispatcher onMethodCall:call result:result];
|
||||
}
|
||||
}];
|
||||
}
|
||||
[self.methodCallDispatcher addMethodName:methodName withHandler:handler];
|
||||
}
|
||||
|
||||
- (void)removeHandlerWithMethodName:(NSString *)methodName {
|
||||
[self.methodCallDispatcher removeHandlerWithMethodName:methodName];
|
||||
}
|
||||
|
||||
- (void)clearAllHandler {
|
||||
[self.methodCallDispatcher clearAllHandler];
|
||||
}
|
||||
|
||||
@end
|
20
ios/Classes/Category/MAAnnotationView+Flutter.h
Normal file
20
ios/Classes/Category/MAAnnotationView+Flutter.h
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// MAAnnotationView+Flutter.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/5.
|
||||
//
|
||||
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AMapMarker;
|
||||
|
||||
@interface MAAnnotationView (Flutter)
|
||||
|
||||
- (void)updateViewWithMarker:(AMapMarker *)marker;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
40
ios/Classes/Category/MAAnnotationView+Flutter.m
Normal file
40
ios/Classes/Category/MAAnnotationView+Flutter.m
Normal file
@ -0,0 +1,40 @@
|
||||
//
|
||||
// MAAnnotationView+Flutter.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/5.
|
||||
//
|
||||
|
||||
#import "MAAnnotationView+Flutter.h"
|
||||
#import "AMapMarker.h"
|
||||
#import "AMapInfoWindow.h"
|
||||
|
||||
@implementation MAAnnotationView (Flutter)
|
||||
|
||||
- (void)updateViewWithMarker:(AMapMarker *)marker {
|
||||
if (marker == nil) {
|
||||
return;
|
||||
}
|
||||
self.alpha = marker.alpha;
|
||||
self.image = marker.image;
|
||||
//anchor变换成地图centerOffset
|
||||
if (self.image) {
|
||||
CGSize imageSize = self.image.size;
|
||||
//iOS的annotationView的中心默认位于annotation的坐标位置,对应的锚点为(0.5,0.5)
|
||||
CGFloat offsetW = imageSize.width * (0.5 - marker.anchor.x);
|
||||
CGFloat offsetH = imageSize.height * (0.5 - marker.anchor.y);
|
||||
self.centerOffset = CGPointMake(offsetW, offsetH);
|
||||
}
|
||||
self.enabled = marker.clickable;
|
||||
self.draggable = marker.draggable;
|
||||
// marker.flat;//flat属性,iOS暂时不开
|
||||
self.canShowCallout = marker.infoWindowEnable;
|
||||
// TODO: 气泡的锚点,由于iOS中的气泡,区分默认气泡和自定义气泡,且无法获得气泡的大小,所以没法将其锚点转换为calloutOffset
|
||||
// self.calloutOffset = marker.infoWindow.anchor;
|
||||
//角度旋转
|
||||
self.imageView.transform = CGAffineTransformMakeRotation(marker.rotation / 180.f * M_PI);
|
||||
self.hidden = (!marker.visible);
|
||||
self.zIndex = marker.zIndex;
|
||||
}
|
||||
|
||||
@end
|
30
ios/Classes/Category/MAMapView+Flutter.h
Normal file
30
ios/Classes/Category/MAMapView+Flutter.h
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// MAMapView+Flutter.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/10/30.
|
||||
//
|
||||
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AMapCameraPosition;
|
||||
@class AMapOption;
|
||||
@protocol FlutterPluginRegistrar;
|
||||
|
||||
@interface MAMapView (Flutter)
|
||||
|
||||
- (void)setCameraPosition:(AMapCameraPosition *)cameraPosition animated:(BOOL)animated duration:(CFTimeInterval)duration;
|
||||
|
||||
/// 获取地图的当前cameraPostion
|
||||
- (AMapCameraPosition *)getCurrentCameraPosition;
|
||||
|
||||
/// 地图camera更新操作
|
||||
- (void)setCameraUpdateDict:(NSDictionary *)updateDict;
|
||||
|
||||
- (void)updateMapViewOption:(NSDictionary *)dict withRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
222
ios/Classes/Category/MAMapView+Flutter.m
Normal file
222
ios/Classes/Category/MAMapView+Flutter.m
Normal file
@ -0,0 +1,222 @@
|
||||
//
|
||||
// MAMapView+Flutter.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/10/30.
|
||||
//
|
||||
|
||||
#import "MAMapView+Flutter.h"
|
||||
#import "AMapCameraPosition.h"
|
||||
#import "AMapConvertUtil.h"
|
||||
#import "AMapJsonUtils.h"
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
@implementation MAMapView (Flutter)
|
||||
|
||||
- (void)setCameraPosition:(AMapCameraPosition *)cameraPosition animated:(BOOL)animated duration:(CFTimeInterval)duration {
|
||||
if (cameraPosition == nil) {
|
||||
return;
|
||||
}
|
||||
MAMapStatus *mapStatus = [MAMapStatus statusWithCenterCoordinate:cameraPosition.target
|
||||
zoomLevel:cameraPosition.zoom
|
||||
rotationDegree:cameraPosition.bearing
|
||||
cameraDegree:cameraPosition.tilt
|
||||
screenAnchor:self.screenAnchor];
|
||||
[self setMapStatus:mapStatus animated:animated duration:duration];
|
||||
}
|
||||
|
||||
- (AMapCameraPosition *)getCurrentCameraPosition {
|
||||
AMapCameraPosition *position = [[AMapCameraPosition alloc] init];
|
||||
position.target = self.centerCoordinate;
|
||||
position.zoom = self.zoomLevel;
|
||||
position.bearing = self.rotationDegree;
|
||||
position.tilt = self.cameraDegree;
|
||||
return position;
|
||||
}
|
||||
|
||||
- (void)setCameraUpdateDict:(NSDictionary *)updateDict {
|
||||
if (updateDict == nil || updateDict.count == 0) {
|
||||
return;
|
||||
}
|
||||
BOOL animated;
|
||||
if ([updateDict[@"animated"] isKindOfClass:[NSNull class]]) {
|
||||
animated = NO;
|
||||
} else {
|
||||
animated = [updateDict[@"animated"] boolValue];
|
||||
}
|
||||
double duration;
|
||||
if ([updateDict[@"duration"] isKindOfClass:[NSNull class]]) {
|
||||
duration = 0;
|
||||
} else {
|
||||
duration = [updateDict[@"duration"] doubleValue]/1000.0;
|
||||
}
|
||||
NSArray *cameraUpdate = updateDict[@"cameraUpdate"];
|
||||
//后面的操作时数组,第一个是操作符,后面才是真的参数;
|
||||
NSAssert(cameraUpdate.count >= 1, @"cameraUpdate 参数错误");
|
||||
NSString *operation = cameraUpdate.firstObject;
|
||||
if ([operation isEqualToString:@"newCameraPosition"] && cameraUpdate.count == 2) {//按照cameraPositon移动
|
||||
AMapCameraPosition *newCameraPosition = [AMapJsonUtils modelFromDict:cameraUpdate[1] modelClass:[AMapCameraPosition class]];
|
||||
[self setCameraPosition:newCameraPosition animated:animated duration:duration];
|
||||
} else if ([operation isEqualToString:@"newLatLng"] && cameraUpdate.count == 2) {//只移动屏幕中心点
|
||||
CLLocationCoordinate2D position = [AMapConvertUtil coordinateFromArray:cameraUpdate[1]];
|
||||
MAMapStatus *currentStatus = [self getMapStatus];
|
||||
currentStatus.centerCoordinate = position;
|
||||
[self setMapStatus:currentStatus animated:animated duration:duration];
|
||||
} else if ([operation isEqualToString:@"newLatLngBounds"] && cameraUpdate.count == 3) {//设置视图的显示范围和边界
|
||||
// TODO: 这里没有使用参数duration
|
||||
MAMapRect boundRect = [AMapConvertUtil mapRectFromArray:cameraUpdate[1]];
|
||||
double padding = [cameraUpdate[2] doubleValue];
|
||||
UIEdgeInsets inset = UIEdgeInsetsMake(padding, padding, padding, padding);
|
||||
[self setVisibleMapRect:boundRect edgePadding:inset animated:animated];
|
||||
} else if ([operation isEqualToString:@"newLatLngZoom"] && cameraUpdate.count == 3) {//设置地图中心点和zoomLevel
|
||||
CLLocationCoordinate2D position = [AMapConvertUtil coordinateFromArray:cameraUpdate[1]];
|
||||
CGFloat zoomLevel = [cameraUpdate[2] floatValue];
|
||||
MAMapStatus *currentStatus = [self getMapStatus];
|
||||
currentStatus.centerCoordinate = position;
|
||||
currentStatus.zoomLevel = zoomLevel;
|
||||
[self setMapStatus:currentStatus animated:animated duration:duration];
|
||||
} else if ([operation isEqualToString:@"scrollBy"] && cameraUpdate.count == 3) {//按照屏幕像素点移动
|
||||
CGPoint pixelPointOffset = CGPointMake([cameraUpdate[1] doubleValue], [cameraUpdate[2] doubleValue]);
|
||||
CGPoint updateCenter = CGPointMake(self.center.x + pixelPointOffset.x/[UIScreen mainScreen].scale, self.center.y + pixelPointOffset.y/[UIScreen mainScreen].scale);
|
||||
CLLocationCoordinate2D centerCoord = [self convertPoint:updateCenter toCoordinateFromView:self];
|
||||
MAMapStatus *currentStatus = [self getMapStatus];
|
||||
currentStatus.centerCoordinate = centerCoord;
|
||||
[self setMapStatus:currentStatus animated:animated duration:duration];
|
||||
} else if ([operation isEqualToString:@"zoomIn"]) {
|
||||
MAMapStatus *currentStatus = [self getMapStatus];
|
||||
currentStatus.zoomLevel = currentStatus.zoomLevel + 1;
|
||||
[self setMapStatus:currentStatus animated:animated duration:duration];
|
||||
} else if ([operation isEqualToString:@"zoomOut"]) {
|
||||
MAMapStatus *currentStatus = [self getMapStatus];
|
||||
currentStatus.zoomLevel = currentStatus.zoomLevel - 1;
|
||||
[self setMapStatus:currentStatus animated:animated duration:duration];
|
||||
} else if ([operation isEqualToString:@"zoomTo"] && cameraUpdate.count == 2) {
|
||||
MAMapStatus *currentStatus = [self getMapStatus];
|
||||
currentStatus.zoomLevel = [cameraUpdate[1] doubleValue];
|
||||
[self setMapStatus:currentStatus animated:animated duration:duration];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)updateMapViewOption:(NSDictionary *)dict withRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
if ([dict isKindOfClass:[NSDictionary class]] == NO || dict == nil || dict.count == 0) {
|
||||
return;
|
||||
}
|
||||
//地图类型
|
||||
NSNumber *mapType = dict[@"mapType"];
|
||||
if (mapType) {
|
||||
self.mapType = mapType.integerValue;
|
||||
}
|
||||
NSDictionary *customStyleOptions = dict[@"customStyleOptions"];
|
||||
if (customStyleOptions) {
|
||||
BOOL customMapStyleEnabled = [customStyleOptions[@"enabled"] boolValue];
|
||||
self.customMapStyleEnabled = customMapStyleEnabled;
|
||||
if (customMapStyleEnabled) {
|
||||
MAMapCustomStyleOptions *styleOption = [[MAMapCustomStyleOptions alloc] init];
|
||||
styleOption.styleData = ((FlutterStandardTypedData*)customStyleOptions[@"styleData"]).data;
|
||||
styleOption.styleExtraData = ((FlutterStandardTypedData*)customStyleOptions[@"styleExtraData"]).data;
|
||||
[self setCustomMapStyleOptions:styleOption];
|
||||
}
|
||||
}
|
||||
|
||||
NSDictionary *locationStyleDict = dict[@"myLocationStyle"];
|
||||
if (locationStyleDict) {
|
||||
BOOL showUserLocation = [locationStyleDict[@"enabled"] boolValue];
|
||||
self.showsUserLocation = showUserLocation;
|
||||
if (showUserLocation) {
|
||||
self.userTrackingMode = MAUserTrackingModeNone;//强制设置为非追随模式,追随模式后续在demo中,使用自定义定位样式实现
|
||||
if (locationStyleDict[@"circleFillColor"] != nil
|
||||
|| locationStyleDict[@"circleStrokeColor"] != nil
|
||||
|| locationStyleDict[@"circleStrokeWidth"] != nil
|
||||
|| locationStyleDict[@"icon"] != nil) {//自定义样式有不为空的属性时,才启动自定义的样式设置
|
||||
MAUserLocationRepresentation *locationStyle = [[MAUserLocationRepresentation alloc] init];
|
||||
if (locationStyleDict[@"circleFillColor"]) {
|
||||
locationStyle.fillColor = [AMapConvertUtil colorFromNumber:locationStyleDict[@"circleFillColor"]];
|
||||
}
|
||||
if (locationStyleDict[@"circleStrokeColor"]) {
|
||||
locationStyle.strokeColor = [AMapConvertUtil colorFromNumber:locationStyleDict[@"circleStrokeColor"]];
|
||||
}
|
||||
if (locationStyleDict[@"circleStrokeWidth"]) {
|
||||
locationStyle.lineWidth = [locationStyleDict[@"circleStrokeWidth"] doubleValue];
|
||||
}
|
||||
if (locationStyleDict[@"icon"]) {
|
||||
locationStyle.image = [AMapConvertUtil imageFromRegistrar:registrar iconData:locationStyleDict[@"icon"]];
|
||||
}
|
||||
[self updateUserLocationRepresentation:locationStyle];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///地图锚点
|
||||
NSArray *screenAnchor = dict[@"screenAnchor"];
|
||||
if (screenAnchor) {
|
||||
CGPoint anchorPoint = [AMapConvertUtil pointFromArray:screenAnchor];
|
||||
self.screenAnchor = anchorPoint;
|
||||
}
|
||||
|
||||
//缩放级别范围
|
||||
NSArray* zoomData = dict[@"minMaxZoomPreference"];
|
||||
if (zoomData) {
|
||||
CGFloat minZoom = (zoomData[0] == [NSNull null]) ? 3.0 : [zoomData[0] doubleValue];
|
||||
self.minZoomLevel = minZoom;
|
||||
CGFloat maxZoom = (zoomData[1] == [NSNull null]) ? 20.0 : [zoomData[1] doubleValue];
|
||||
self.maxZoomLevel = maxZoom;
|
||||
}
|
||||
NSArray *limitBounds = dict[@"limitBounds"];
|
||||
if (limitBounds) {
|
||||
MAMapRect limitRect = [AMapConvertUtil mapRectFromArray:limitBounds];
|
||||
self.limitMapRect = limitRect;
|
||||
}
|
||||
//显示路况开关
|
||||
NSNumber *showTraffic = dict[@"trafficEnabled"];
|
||||
if (showTraffic) {
|
||||
self.showTraffic = [showTraffic boolValue];
|
||||
}
|
||||
// 地图poi是否允许点击
|
||||
NSNumber *touchPOIEnable = dict[@"touchPoiEnabled"];
|
||||
if (touchPOIEnable) {
|
||||
self.touchPOIEnabled = [touchPOIEnable boolValue];
|
||||
}
|
||||
//是否显示3D建筑物
|
||||
NSNumber *showBuilding = dict[@"buildingsEnabled"];
|
||||
if (showBuilding) {
|
||||
self.showsBuildings = [showBuilding boolValue];
|
||||
}
|
||||
//是否显示底图文字标注
|
||||
NSNumber *showLable = dict[@"labelsEnabled"];
|
||||
if (showLable) {
|
||||
self.showsLabels = [showLable boolValue];
|
||||
}
|
||||
//是否显示指南针
|
||||
NSNumber *showCompass = dict[@"compassEnabled"];
|
||||
if (showCompass) {
|
||||
self.showsCompass = [showCompass boolValue];
|
||||
}
|
||||
//是否显示比例尺
|
||||
NSNumber *showScale = dict[@"scaleEnabled"];
|
||||
if (showScale) {
|
||||
self.showsScale = [showScale boolValue];
|
||||
}
|
||||
//是否支持缩放手势
|
||||
NSNumber *zoomEnable = dict[@"zoomGesturesEnabled"];
|
||||
if (zoomEnable) {
|
||||
self.zoomEnabled = [zoomEnable boolValue];
|
||||
}
|
||||
//是否支持滑动手势
|
||||
NSNumber *scrollEnable = dict[@"scrollGesturesEnabled"];
|
||||
if (scrollEnable) {
|
||||
self.scrollEnabled = [scrollEnable boolValue];
|
||||
}
|
||||
//是否支持旋转手势
|
||||
NSNumber *rotateEnable = dict[@"rotateGesturesEnabled"];
|
||||
if (rotateEnable) {
|
||||
self.rotateEnabled = [rotateEnable boolValue];
|
||||
}
|
||||
//是否支持仰角手势
|
||||
NSNumber *rotateCameraEnable = dict[@"tiltGesturesEnabled"];
|
||||
if (rotateCameraEnable) {
|
||||
self.rotateCameraEnabled = [rotateCameraEnable boolValue];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
29
ios/Classes/Category/MAPointAnnotation+Flutter.h
Normal file
29
ios/Classes/Category/MAPointAnnotation+Flutter.h
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// MAPointAnnotation+Flutter.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/9.
|
||||
//
|
||||
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// AnnotationView的复用标识
|
||||
extern NSString *const AMapFlutterAnnotationViewIdentifier;
|
||||
|
||||
/// 该拓展类型主要用于对地图原PointAnnotation添加一个唯一id,
|
||||
/// 便于在地图回调代理中,通过id快速找到对应的AMapMarker对象,
|
||||
/// 以此来构建对应的MAAnnotatioView
|
||||
@interface MAPointAnnotation (Flutter)
|
||||
|
||||
//为Annotation拓展存储的flutter传入的markerId,便于快速查找对应的marker数据
|
||||
@property (nullable,nonatomic,copy,readonly) NSString *markerId;
|
||||
|
||||
/// 使用MarkerId初始化对应的Annotation
|
||||
/// @param markerId marker的唯一标识
|
||||
- (instancetype)initWithMarkerId:(NSString *)markerId;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
31
ios/Classes/Category/MAPointAnnotation+Flutter.m
Normal file
31
ios/Classes/Category/MAPointAnnotation+Flutter.m
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// MAPointAnnotation+Flutter.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/9.
|
||||
//
|
||||
|
||||
#import "MAPointAnnotation+Flutter.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
NSString *const AMapFlutterAnnotationViewIdentifier = @"AMapFlutterAnnotationViewIdentifier";
|
||||
|
||||
@implementation MAPointAnnotation (Flutter)
|
||||
|
||||
- (NSString *)markerId {
|
||||
return objc_getAssociatedObject(self, @selector(markerId));
|
||||
}
|
||||
|
||||
- (void)setMarkerId:(NSString * _Nonnull)markerId {
|
||||
objc_setAssociatedObject(self, @selector(markerId), markerId, OBJC_ASSOCIATION_COPY);
|
||||
}
|
||||
|
||||
- (instancetype)initWithMarkerId:(NSString *)markerId {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.markerId = markerId;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
26
ios/Classes/Category/MAPolygon+Flutter.h
Normal file
26
ios/Classes/Category/MAPolygon+Flutter.h
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// MAPolygon+Flutter.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 该拓展类型主要用于对地图原MAPolygon添加一个唯一id,
|
||||
/// 便于在地图回调代理中,通过id快速找到对应的AMapPolyline对象,
|
||||
/// 以此来构建对应的polygonRender
|
||||
|
||||
@interface MAPolygon (Flutter)
|
||||
|
||||
@property (nonatomic,copy,readonly) NSString *polygonId;
|
||||
|
||||
/// 使用polygonId初始化对应的MAPolygon
|
||||
/// @param polygonId polylgon的唯一标识
|
||||
- (instancetype)initWithPolygonId:(NSString *)polygonId;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
29
ios/Classes/Category/MAPolygon+Flutter.m
Normal file
29
ios/Classes/Category/MAPolygon+Flutter.m
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// MAPolygon+Flutter.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import "MAPolygon+Flutter.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation MAPolygon (Flutter)
|
||||
|
||||
- (NSString *)polygonId {
|
||||
return objc_getAssociatedObject(self, @selector(polygonId));
|
||||
}
|
||||
|
||||
- (void)setPolygonId:(NSString * _Nonnull)polygonId {
|
||||
objc_setAssociatedObject(self, @selector(polygonId), polygonId, OBJC_ASSOCIATION_COPY);
|
||||
}
|
||||
|
||||
- (instancetype)initWithPolygonId:(NSString *)polygonId {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.polygonId = polygonId;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
20
ios/Classes/Category/MAPolygonRenderer+Flutter.h
Normal file
20
ios/Classes/Category/MAPolygonRenderer+Flutter.h
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// MAPolygonRenderer+Flutter.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AMapPolygon;
|
||||
|
||||
@interface MAPolygonRenderer (Flutter)
|
||||
|
||||
- (void)updateRenderWithPolygon:(AMapPolygon *)polygon;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
26
ios/Classes/Category/MAPolygonRenderer+Flutter.m
Normal file
26
ios/Classes/Category/MAPolygonRenderer+Flutter.m
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// MAPolygonRenderer+Flutter.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import "MAPolygonRenderer+Flutter.h"
|
||||
#import "AMapPolygon.h"
|
||||
|
||||
@implementation MAPolygonRenderer (Flutter)
|
||||
|
||||
- (void)updateRenderWithPolygon:(AMapPolygon *)polygon {
|
||||
self.lineWidth = polygon.strokeWidth;
|
||||
self.strokeColor = polygon.strokeColor;
|
||||
self.fillColor = polygon.fillColor;
|
||||
self.lineJoinType = polygon.joinType;
|
||||
if (polygon.visible) {
|
||||
self.alpha = 1.0;
|
||||
} else {
|
||||
self.alpha = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
26
ios/Classes/Category/MAPolyline+Flutter.h
Normal file
26
ios/Classes/Category/MAPolyline+Flutter.h
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// MAPolyline+Flutter.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/9.
|
||||
//
|
||||
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 该拓展类型主要用于对地图原MAPolyline添加一个唯一id,
|
||||
/// 便于在地图回调代理中,通过id快速找到对应的AMapPolyline对象,
|
||||
/// 以此来构建对应的polylineRender
|
||||
|
||||
@interface MAPolyline (Flutter)
|
||||
|
||||
@property (nonatomic,copy,readonly) NSString *polylineId;
|
||||
|
||||
/// 使用polylineId初始化对应的MAPolyline
|
||||
/// @param polylineId polyline的唯一标识
|
||||
- (instancetype)initWithPolylineId:(NSString *)polylineId;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
29
ios/Classes/Category/MAPolyline+Flutter.m
Normal file
29
ios/Classes/Category/MAPolyline+Flutter.m
Normal file
@ -0,0 +1,29 @@
|
||||
//
|
||||
// MAPolyline+Flutter.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/9.
|
||||
//
|
||||
|
||||
#import "MAPolyline+Flutter.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation MAPolyline (Flutter)
|
||||
|
||||
- (NSString *)polylineId {
|
||||
return objc_getAssociatedObject(self, @selector(polylineId));
|
||||
}
|
||||
|
||||
- (void)setPolylineId:(NSString * _Nonnull)polylineId {
|
||||
objc_setAssociatedObject(self, @selector(polylineId), polylineId, OBJC_ASSOCIATION_COPY);
|
||||
}
|
||||
|
||||
- (instancetype)initWithPolylineId:(NSString *)polylineId {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.polylineId = polylineId;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
20
ios/Classes/Category/MAPolylineRenderer+Flutter.h
Normal file
20
ios/Classes/Category/MAPolylineRenderer+Flutter.h
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// MAPolylineRenderer+Flutter.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/7.
|
||||
//
|
||||
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AMapPolyline;
|
||||
|
||||
@interface MAPolylineRenderer (Flutter)
|
||||
|
||||
- (void)updateRenderWithPolyline:(AMapPolyline *)polyline;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
30
ios/Classes/Category/MAPolylineRenderer+Flutter.m
Normal file
30
ios/Classes/Category/MAPolylineRenderer+Flutter.m
Normal file
@ -0,0 +1,30 @@
|
||||
//
|
||||
// MAPolylineRenderer+Flutter.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/7.
|
||||
//
|
||||
|
||||
#import "MAPolylineRenderer+Flutter.h"
|
||||
#import "AMapPolyline.h"
|
||||
|
||||
@implementation MAPolylineRenderer (Flutter)
|
||||
|
||||
- (void)updateRenderWithPolyline:(AMapPolyline *)polyline {
|
||||
self.lineWidth = polyline.width;
|
||||
self.strokeColor = polyline.color;
|
||||
if (polyline.visible) {//可见时,才设置透明度
|
||||
self.alpha = polyline.alpha;
|
||||
} else {
|
||||
self.alpha = 0;
|
||||
}
|
||||
if (polyline.strokeImage) {
|
||||
self.strokeImage = polyline.strokeImage;
|
||||
}
|
||||
self.lineDashType = polyline.dashLineType;
|
||||
self.lineJoinType = polyline.joinType;
|
||||
self.lineCapType = polyline.capType;
|
||||
self.userInteractionEnabled = YES;//默认可点击
|
||||
}
|
||||
|
||||
@end
|
28
ios/Classes/Model/AMapCameraPosition.h
Normal file
28
ios/Classes/Model/AMapCameraPosition.h
Normal file
@ -0,0 +1,28 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
@class AMapCameraPosition;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma mark - Object interfaces
|
||||
|
||||
@interface AMapCameraPosition : NSObject
|
||||
|
||||
/// 可视区域指向的方向,以角度为单位,从正北向逆时针方向计算,从0 度到360 度。
|
||||
@property (nonatomic, assign) CGFloat bearing;
|
||||
|
||||
/// 目标位置的屏幕中心点经纬度坐标。
|
||||
@property (nonatomic, assign) CLLocationCoordinate2D target;
|
||||
|
||||
/// 目标可视区域的倾斜度,以角度为单位。
|
||||
@property (nonatomic, assign) CGFloat tilt;
|
||||
|
||||
/// 目标可视区域的缩放级别
|
||||
@property (nonatomic, assign) CGFloat zoom;
|
||||
|
||||
- (NSDictionary *)toDictionary;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
21
ios/Classes/Model/AMapCameraPosition.m
Normal file
21
ios/Classes/Model/AMapCameraPosition.m
Normal file
@ -0,0 +1,21 @@
|
||||
#import "AMapCameraPosition.h"
|
||||
#import "AMapConvertUtil.h"
|
||||
|
||||
@implementation AMapCameraPosition
|
||||
|
||||
- (NSDictionary *)toDictionary {
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||
[dict setObject:@(self.bearing) forKey:@"bearing"];
|
||||
[dict setObject:@(self.tilt) forKey:@"tilt"];
|
||||
[dict setObject:@(self.zoom) forKey:@"zoom"];
|
||||
if (CLLocationCoordinate2DIsValid(self.target)) {
|
||||
[dict setObject:[AMapConvertUtil jsonArrayFromCoordinate:self.target] forKey:@"target"];
|
||||
}
|
||||
return [dict copy];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
return [NSString stringWithFormat:@"CameraPosition(bearing:%.6f, target:%@, tilt:%.6f, zoom:%.6f)",self.bearing,[AMapConvertUtil stringFromCoordinate:self.target],self.tilt,self.zoom];
|
||||
}
|
||||
|
||||
@end
|
22
ios/Classes/Model/AMapInfoWindow.h
Normal file
22
ios/Classes/Model/AMapInfoWindow.h
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// AMapInfoWindow.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/3.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AMapInfoWindow : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString* title;
|
||||
|
||||
@property (nonatomic, copy) NSString* snippet;
|
||||
|
||||
@property (nonatomic, assign) CGPoint anchor;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
12
ios/Classes/Model/AMapInfoWindow.m
Normal file
12
ios/Classes/Model/AMapInfoWindow.m
Normal file
@ -0,0 +1,12 @@
|
||||
//
|
||||
// AMapInfoWindow.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/3.
|
||||
//
|
||||
|
||||
#import "AMapInfoWindow.h"
|
||||
|
||||
@implementation AMapInfoWindow
|
||||
|
||||
@end
|
44
ios/Classes/Model/AMapLocation.h
Normal file
44
ios/Classes/Model/AMapLocation.h
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// AMapLocation.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class MAUserLocation;
|
||||
|
||||
@interface AMapLocation : NSObject
|
||||
|
||||
///定位提供者
|
||||
///
|
||||
///iOS平台只会返回'iOS'
|
||||
@property (nonatomic, copy) NSString *provider;
|
||||
|
||||
///经纬度
|
||||
@property (nonatomic, assign) CLLocationCoordinate2D latLng;
|
||||
|
||||
///水平精确度
|
||||
@property (nonatomic, assign) double accuracy;
|
||||
|
||||
///海拔
|
||||
@property (nonatomic, assign) double altitude;
|
||||
|
||||
///角度
|
||||
@property (nonatomic, assign) double bearing;
|
||||
|
||||
///速度
|
||||
@property (nonatomic, assign) double speed;
|
||||
|
||||
///定位时间,单位:毫秒
|
||||
@property (nonatomic, assign) double time;
|
||||
|
||||
- (void)updateWithUserLocation:(CLLocation *)location;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
32
ios/Classes/Model/AMapLocation.m
Normal file
32
ios/Classes/Model/AMapLocation.m
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// AMapLocation.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import "AMapLocation.h"
|
||||
|
||||
@implementation AMapLocation
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.provider = @"iOS";
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateWithUserLocation:(CLLocation *)location {
|
||||
if (location == nil) {
|
||||
return;
|
||||
}
|
||||
self.latLng = location.coordinate;
|
||||
self.accuracy = location.horizontalAccuracy;
|
||||
self.altitude = location.altitude;
|
||||
self.bearing = location.course;
|
||||
self.speed = location.speed;
|
||||
self.time = [location.timestamp timeIntervalSince1970]*1000;
|
||||
}
|
||||
|
||||
@end
|
58
ios/Classes/Model/AMapMarker.h
Normal file
58
ios/Classes/Model/AMapMarker.h
Normal file
@ -0,0 +1,58 @@
|
||||
//
|
||||
// AMapMarker.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/3.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AMapInfoWindow;
|
||||
|
||||
@interface AMapMarker : NSObject
|
||||
|
||||
@property (nonatomic, copy) NSString *id_;
|
||||
|
||||
@property (nonatomic, assign) double alpha;
|
||||
|
||||
@property (nonatomic, assign) CGPoint anchor;
|
||||
|
||||
//原始的图片BitmapDescriptor的json存储结构
|
||||
@property (nonatomic, copy) NSArray *icon;
|
||||
|
||||
//解析后的图片
|
||||
@property (nonatomic, strong) UIImage *image;
|
||||
|
||||
@property (nonatomic, assign) bool clickable;
|
||||
|
||||
@property (nonatomic, assign) bool draggable;
|
||||
|
||||
@property (nonatomic, assign) bool flat;
|
||||
|
||||
@property (nonatomic, assign) bool infoWindowEnable;
|
||||
|
||||
@property (nonatomic, strong) AMapInfoWindow *infoWindow;
|
||||
|
||||
@property (nonatomic, assign) CLLocationCoordinate2D position;
|
||||
|
||||
@property (nonatomic, assign) double rotation;
|
||||
|
||||
@property (nonatomic, assign) bool visible;
|
||||
|
||||
@property (nonatomic, assign) double zIndex;
|
||||
|
||||
//根据以上marker信息生成的对应的iOS端的Annotation
|
||||
@property (nonatomic, strong, readonly) MAPointAnnotation *annotation;
|
||||
|
||||
|
||||
/// 更新marker的信息
|
||||
/// @param changedMarker 带修改信息的marker
|
||||
- (void)updateMarker:(AMapMarker *)changedMarker;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
68
ios/Classes/Model/AMapMarker.m
Normal file
68
ios/Classes/Model/AMapMarker.m
Normal file
@ -0,0 +1,68 @@
|
||||
//
|
||||
// AMapMarker.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/3.
|
||||
//
|
||||
|
||||
#import "AMapMarker.h"
|
||||
#import "AMapInfoWindow.h"
|
||||
#import "MAPointAnnotation+Flutter.h"
|
||||
|
||||
@interface AMapMarker ()
|
||||
|
||||
@property (nonatomic, strong, readwrite) MAPointAnnotation *annotation;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AMapMarker
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_alpha = 1.0;
|
||||
_clickable = YES;
|
||||
_draggable = NO;
|
||||
_visible = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (MAPointAnnotation *)annotation {
|
||||
if (_annotation == nil) {
|
||||
NSAssert(self.id_ != nil, @"markerid不能为空");
|
||||
_annotation = [[MAPointAnnotation alloc] initWithMarkerId:self.id_];
|
||||
[self _updateAnnotation];
|
||||
}
|
||||
return _annotation;
|
||||
}
|
||||
|
||||
/// 更新marker的信息
|
||||
/// @param changedMarker 带修改信息的marker
|
||||
- (void)updateMarker:(AMapMarker *)changedMarker {
|
||||
NSAssert((changedMarker != nil && [self.id_ isEqualToString:changedMarker.id_]), @"更新marker数据异常");
|
||||
self.alpha = changedMarker.alpha;
|
||||
self.anchor = changedMarker.anchor;
|
||||
self.clickable = changedMarker.clickable;
|
||||
self.draggable = changedMarker.draggable;
|
||||
self.flat = changedMarker.flat;
|
||||
self.infoWindowEnable = changedMarker.infoWindowEnable;
|
||||
self.infoWindow = changedMarker.infoWindow;
|
||||
self.position = changedMarker.position;
|
||||
self.rotation = changedMarker.rotation;
|
||||
self.visible = changedMarker.visible;
|
||||
self.zIndex = changedMarker.zIndex;
|
||||
|
||||
if (_annotation) {//Annotation已经被添加,则直接更新其数据
|
||||
[self _updateAnnotation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_updateAnnotation {
|
||||
_annotation.title = self.infoWindow.title;
|
||||
_annotation.subtitle = self.infoWindow.snippet;
|
||||
_annotation.coordinate = self.position;
|
||||
}
|
||||
|
||||
|
||||
@end
|
44
ios/Classes/Model/AMapPolygon.h
Normal file
44
ios/Classes/Model/AMapPolygon.h
Normal file
@ -0,0 +1,44 @@
|
||||
//
|
||||
// AMapPolygon.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AMapPolygon : NSObject{
|
||||
/// 覆盖物的坐标点数组,key为@"points"
|
||||
CLLocationCoordinate2D *_coords;//坐标的数组指针
|
||||
NSUInteger _coordCount;//坐标的个数
|
||||
}
|
||||
|
||||
@property (nonatomic, copy) NSString *id_;
|
||||
|
||||
/// 边框宽度
|
||||
@property (nonatomic, assign) CGFloat strokeWidth;
|
||||
|
||||
/// 边框颜色
|
||||
@property (nonatomic, strong) UIColor *strokeColor;
|
||||
|
||||
/// 填充颜色
|
||||
@property (nonatomic, strong) UIColor *fillColor;
|
||||
|
||||
/// 是否可见
|
||||
@property (nonatomic, assign) bool visible;
|
||||
|
||||
/// 连接点类型
|
||||
@property (nonatomic, assign) MALineJoinType joinType;
|
||||
|
||||
/// 由以上数据生成的polyline对象
|
||||
@property (nonatomic, strong,readonly) MAPolygon *polygon;
|
||||
|
||||
- (void)updatePolygon:(AMapPolygon *)polygon;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
97
ios/Classes/Model/AMapPolygon.m
Normal file
97
ios/Classes/Model/AMapPolygon.m
Normal file
@ -0,0 +1,97 @@
|
||||
//
|
||||
// AMapPolygon.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import "AMapPolygon.h"
|
||||
#import "AMapConvertUtil.h"
|
||||
#import "MAPolygon+Flutter.h"
|
||||
|
||||
@interface AMapPolygon ()
|
||||
|
||||
@property (nonatomic, strong,readwrite) MAPolygon *polygon;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation AMapPolygon
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_visible = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)postHookWith:(NSDictionary *)dict {
|
||||
NSArray *points = dict[@"points"];
|
||||
NSAssert(points.count > 0, @"polygon传入的经纬度点有误!");
|
||||
//如果经纬度点已经有值,需要手动释放内存
|
||||
if (_coords != NULL) {
|
||||
free(_coords);
|
||||
_coords = NULL;
|
||||
}
|
||||
_coordCount = points.count;
|
||||
_coords = (CLLocationCoordinate2D*)malloc(_coordCount * sizeof(CLLocationCoordinate2D));
|
||||
for (NSUInteger index = 0; index < _coordCount; index ++) {
|
||||
NSArray *point = points[index];
|
||||
_coords[index] = [AMapConvertUtil coordinateFromArray:point];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (_coords != NULL) {
|
||||
free(_coords);
|
||||
_coords = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (MAPolygon *)polygon {
|
||||
if (_polygon == nil) {
|
||||
_polygon = [[MAPolygon alloc] initWithPolygonId:self.id_];
|
||||
[_polygon setPolygonWithCoordinates:_coords count:_coordCount];
|
||||
}
|
||||
return _polygon;
|
||||
}
|
||||
|
||||
//更新polyline
|
||||
- (void)updatePolygon:(AMapPolygon *)polygon {
|
||||
NSAssert((polygon != nil && [self.id_ isEqualToString:polygon.id_]), @"更新AMapPolygon数据异常");
|
||||
if ([self checkCoordsEqualWithPolyline:polygon] == NO) {//polyline更新了经纬度坐标
|
||||
if (_coords != NULL) {
|
||||
free(_coords);
|
||||
_coords = NULL;
|
||||
}
|
||||
_coordCount = polygon->_coordCount;
|
||||
_coords = (CLLocationCoordinate2D*)malloc(_coordCount * sizeof(CLLocationCoordinate2D));
|
||||
for (NSUInteger index = 0; index < _coordCount; index ++) {
|
||||
_coords[index] = polygon->_coords[index];
|
||||
}
|
||||
}
|
||||
self.strokeWidth = polygon.strokeWidth;
|
||||
self.strokeColor = polygon.strokeColor;
|
||||
self.fillColor = polygon.fillColor;
|
||||
self.visible = polygon.visible;
|
||||
self.joinType = polygon.joinType;
|
||||
if (_polygon) {
|
||||
[_polygon setPolygonWithCoordinates:_coords count:_coordCount];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)checkCoordsEqualWithPolyline:(AMapPolygon *)newPolygon {
|
||||
if (_coordCount != newPolygon->_coordCount) {//数量不同,则直接更新
|
||||
return NO;
|
||||
}
|
||||
for (NSUInteger index = 0; index < _coordCount; index++) {
|
||||
if ([AMapConvertUtil isEqualWith:_coords[index] to:newPolygon->_coords[index]] == NO) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
@end
|
60
ios/Classes/Model/AMapPolyline.h
Normal file
60
ios/Classes/Model/AMapPolyline.h
Normal file
@ -0,0 +1,60 @@
|
||||
//
|
||||
// AMapPolyline.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/6.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AMapPolyline : NSObject {
|
||||
/// 覆盖物的坐标点数组,key为@"points"
|
||||
CLLocationCoordinate2D *_coords;//坐标的数组指针
|
||||
NSUInteger _coordCount;//坐标的个数
|
||||
}
|
||||
|
||||
@property (nonatomic, copy) NSString *id_;
|
||||
|
||||
/// 线宽
|
||||
@property (nonatomic, assign) CGFloat width;
|
||||
|
||||
/// 覆盖物颜色,默认值为(0xCCC4E0F0).
|
||||
@property (nonatomic, strong) UIColor *color;
|
||||
|
||||
/// 是否可见
|
||||
@property (nonatomic, assign) bool visible;
|
||||
|
||||
/// 透明度
|
||||
@property (nonatomic, assign) CGFloat alpha;
|
||||
|
||||
/// 自定义纹理图片
|
||||
@property (nonatomic, copy) NSArray *customTexture;
|
||||
|
||||
/// 由customTexture解析生成的图片
|
||||
@property (nonatomic, strong) UIImage *strokeImage;
|
||||
|
||||
/// 是否为大地曲线
|
||||
@property (nonatomic, assign) BOOL geodesic;
|
||||
|
||||
/// 虚线类型
|
||||
@property (nonatomic, assign) MALineDashType dashLineType;
|
||||
|
||||
/// 连接点类型
|
||||
@property (nonatomic, assign) MALineJoinType joinType;
|
||||
|
||||
/// 线头类型
|
||||
@property (nonatomic, assign) MALineCapType capType;
|
||||
|
||||
/// 由以上数据生成的polyline对象
|
||||
@property (nonatomic, strong, readonly) MAPolyline *polyline;
|
||||
|
||||
//更新polyline
|
||||
- (void)updatePolyline:(AMapPolyline *)polyline;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
104
ios/Classes/Model/AMapPolyline.m
Normal file
104
ios/Classes/Model/AMapPolyline.m
Normal file
@ -0,0 +1,104 @@
|
||||
//
|
||||
// AMapPolyline.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/6.
|
||||
//
|
||||
|
||||
#import "AMapPolyline.h"
|
||||
#import "AMapConvertUtil.h"
|
||||
#import "MAPolyline+Flutter.h"
|
||||
|
||||
@interface AMapPolyline ()
|
||||
|
||||
@property (nonatomic, strong, readwrite) MAPolyline *polyline;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation AMapPolyline
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_alpha = 1.0;
|
||||
_visible = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)postHookWith:(NSDictionary *)dict {
|
||||
NSArray *points = dict[@"points"];
|
||||
NSAssert(points.count > 0, @"polyline传入的经纬度点有误!");
|
||||
//如果经纬度点已经有值,需要手动释放内存
|
||||
if (_coords != NULL) {
|
||||
free(_coords);
|
||||
_coords = NULL;
|
||||
}
|
||||
_coordCount = points.count;
|
||||
_coords = (CLLocationCoordinate2D*)malloc(_coordCount * sizeof(CLLocationCoordinate2D));
|
||||
for (NSUInteger index = 0; index < _coordCount; index ++) {
|
||||
NSArray *point = points[index];
|
||||
_coords[index] = [AMapConvertUtil coordinateFromArray:point];
|
||||
}
|
||||
}
|
||||
|
||||
- (MAPolyline *)polyline {
|
||||
if (_polyline == nil) {
|
||||
if (self.geodesic) {//如果是大地曲线,则使用对应的类型
|
||||
_polyline = [[MAGeodesicPolyline alloc] initWithPolylineId:self.id_];
|
||||
} else {
|
||||
_polyline = [[MAPolyline alloc] initWithPolylineId:self.id_];
|
||||
}
|
||||
[_polyline setPolylineWithCoordinates:_coords count:_coordCount];
|
||||
}
|
||||
return _polyline;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (_coords != NULL) {
|
||||
free(_coords);
|
||||
_coords = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//更新polyline
|
||||
- (void)updatePolyline:(AMapPolyline *)polyline {
|
||||
NSAssert((polyline != nil && [self.id_ isEqualToString:polyline.id_]), @"更新Polyline数据异常");
|
||||
if ([self checkCoordsEqualWithPolyline:polyline] == NO) {//polyline更新了经纬度坐标
|
||||
if (_coords != NULL) {
|
||||
free(_coords);
|
||||
_coords = NULL;
|
||||
}
|
||||
_coordCount = polyline->_coordCount;
|
||||
_coords = (CLLocationCoordinate2D*)malloc(_coordCount * sizeof(CLLocationCoordinate2D));
|
||||
for (NSUInteger index = 0; index < _coordCount; index ++) {
|
||||
_coords[index] = polyline->_coords[index];
|
||||
}
|
||||
}
|
||||
self.width = polyline.width;
|
||||
self.color = polyline.color;
|
||||
self.visible = polyline.visible;
|
||||
self.alpha = polyline.alpha;
|
||||
NSAssert(self.geodesic == polyline.geodesic, @"是否为大地曲线的变量,不允许动态修改");
|
||||
self.dashLineType = polyline.dashLineType;
|
||||
self.joinType = polyline.joinType;
|
||||
self.capType = polyline.capType;
|
||||
if (_polyline) {
|
||||
[_polyline setPolylineWithCoordinates:_coords count:_coordCount];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)checkCoordsEqualWithPolyline:(AMapPolyline *)newPolyline {
|
||||
if (_coordCount != newPolyline->_coordCount) {//数量不同,则直接更新
|
||||
return NO;
|
||||
}
|
||||
for (NSUInteger index = 0; index < _coordCount; index++) {
|
||||
if ([AMapConvertUtil isEqualWith:_coords[index] to:newPolyline->_coords[index]] == NO) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
40
ios/Classes/OverlayController/AMapMarkerController.h
Normal file
40
ios/Classes/OverlayController/AMapMarkerController.h
Normal file
@ -0,0 +1,40 @@
|
||||
//
|
||||
// AMapMarkerController.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/3.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Flutter/Flutter.h>
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AMapMarker;
|
||||
|
||||
@interface AMapMarkerController : NSObject
|
||||
|
||||
- (instancetype)init:(FlutterMethodChannel*)methodChannel
|
||||
mapView:(MAMapView*)mapView
|
||||
registrar:(NSObject<FlutterPluginRegistrar>*)registrar;
|
||||
|
||||
- (nullable AMapMarker *)markerForId:(NSString *)markerId;
|
||||
|
||||
- (void)addMarkers:(NSArray*)markersToAdd;
|
||||
|
||||
- (void)changeMarkers:(NSArray*)markersToChange;
|
||||
|
||||
- (void)removeMarkerIds:(NSArray*)markerIdsToRemove;
|
||||
|
||||
//MARK: Marker的回调
|
||||
|
||||
- (BOOL)onMarkerTap:(NSString*)markerId;
|
||||
|
||||
- (BOOL)onMarker:(NSString *)markerId endPostion:(CLLocationCoordinate2D)position;
|
||||
|
||||
//- (BOOL)onInfoWindowTap:(NSString *)markerId;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
153
ios/Classes/OverlayController/AMapMarkerController.m
Normal file
153
ios/Classes/OverlayController/AMapMarkerController.m
Normal file
@ -0,0 +1,153 @@
|
||||
//
|
||||
// AMapMarkerController.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/3.
|
||||
//
|
||||
|
||||
#import "AMapMarkerController.h"
|
||||
#import "AMapMarker.h"
|
||||
#import "AMapJsonUtils.h"
|
||||
#import "AMapConvertUtil.h"
|
||||
#import "MAAnnotationView+Flutter.h"
|
||||
#import "FlutterMethodChannel+MethodCallDispatch.h"
|
||||
|
||||
@interface AMapMarkerController ()
|
||||
|
||||
@property (nonatomic,strong) NSMutableDictionary<NSString*,AMapMarker*> *markerDict;
|
||||
@property (nonatomic,strong) FlutterMethodChannel *methodChannel;
|
||||
@property (nonatomic,strong) NSObject<FlutterPluginRegistrar> *registrar;
|
||||
@property (nonatomic,strong) MAMapView *mapView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AMapMarkerController
|
||||
|
||||
- (instancetype)init:(FlutterMethodChannel*)methodChannel
|
||||
mapView:(MAMapView*)mapView
|
||||
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_methodChannel = methodChannel;
|
||||
_mapView = mapView;
|
||||
_markerDict = [NSMutableDictionary dictionaryWithCapacity:1];
|
||||
_registrar = registrar;
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[_methodChannel addMethodName:@"markers#update" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
id markersToAdd = call.arguments[@"markersToAdd"];
|
||||
if ([markersToAdd isKindOfClass:[NSArray class]]) {
|
||||
[weakSelf addMarkers:markersToAdd];
|
||||
}
|
||||
id markersToChange = call.arguments[@"markersToChange"];
|
||||
if ([markersToChange isKindOfClass:[NSArray class]]) {
|
||||
[weakSelf changeMarkers:markersToChange];
|
||||
}
|
||||
id markerIdsToRemove = call.arguments[@"markerIdsToRemove"];
|
||||
if ([markerIdsToRemove isKindOfClass:[NSArray class]]) {
|
||||
[weakSelf removeMarkerIds:markerIdsToRemove];
|
||||
}
|
||||
result(nil);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable AMapMarker *)markerForId:(NSString *)markerId {
|
||||
return _markerDict[markerId];
|
||||
}
|
||||
|
||||
- (void)addMarkers:(NSArray*)markersToAdd {
|
||||
for (NSDictionary* marker in markersToAdd) {
|
||||
AMapMarker *markerModel = [AMapJsonUtils modelFromDict:marker modelClass:[AMapMarker class]];
|
||||
//从bitmapDesc中解析UIImage
|
||||
if (markerModel.icon) {
|
||||
markerModel.image = [AMapConvertUtil imageFromRegistrar:self.registrar iconData:markerModel.icon];
|
||||
}
|
||||
// 先加入到字段中,避免后续的地图回到里,取不到对应的marker数据
|
||||
if (markerModel.id_) {
|
||||
_markerDict[markerModel.id_] = markerModel;
|
||||
}
|
||||
[self.mapView addAnnotation:markerModel.annotation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)changeMarkers:(NSArray*)markersToChange {
|
||||
for (NSDictionary* markerToChange in markersToChange) {
|
||||
NSLog(@"changeMarker:%@",markerToChange);
|
||||
AMapMarker *markerModelToChange = [AMapJsonUtils modelFromDict:markerToChange modelClass:[AMapMarker class]];
|
||||
AMapMarker *currentMarkerModel = _markerDict[markerModelToChange.id_];
|
||||
NSAssert(currentMarkerModel != nil, @"需要修改的marker不存在");
|
||||
|
||||
//如果图标变了,则存储和解析新的图标
|
||||
if ([AMapConvertUtil checkIconDescriptionChangedFrom:currentMarkerModel.icon to:markerModelToChange.icon]) {
|
||||
UIImage *image = [AMapConvertUtil imageFromRegistrar:self.registrar iconData:markerModelToChange.icon];
|
||||
currentMarkerModel.icon = markerModelToChange.icon;
|
||||
currentMarkerModel.image = image;
|
||||
}
|
||||
//更新除了图标之外的其它信息
|
||||
[currentMarkerModel updateMarker:markerModelToChange];
|
||||
|
||||
MAAnnotationView *view = [self.mapView viewForAnnotation:currentMarkerModel.annotation];
|
||||
if (view) {//如果可以获取到View,则立刻更新
|
||||
[view updateViewWithMarker:currentMarkerModel];
|
||||
} //获取不到时,则在viewDidAdd的回调中,重新更新view的效果;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeMarkerIds:(NSArray*)markerIdsToRemove {
|
||||
for (NSString* markerId in markerIdsToRemove) {
|
||||
if (!markerId) {
|
||||
continue;
|
||||
}
|
||||
AMapMarker* marker = _markerDict[markerId];
|
||||
if (!marker) {
|
||||
continue;
|
||||
}
|
||||
[self.mapView removeAnnotation:marker.annotation];
|
||||
[_markerDict removeObjectForKey:markerId];
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: Marker的回调
|
||||
|
||||
- (BOOL)onMarkerTap:(NSString*)markerId {
|
||||
if (!markerId) {
|
||||
return NO;
|
||||
}
|
||||
AMapMarker* marker = _markerDict[markerId];
|
||||
if (!marker) {
|
||||
return NO;
|
||||
}
|
||||
[_methodChannel invokeMethod:@"marker#onTap" arguments:@{@"markerId" : markerId}];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)onMarker:(NSString *)markerId endPostion:(CLLocationCoordinate2D)position {
|
||||
if (!markerId) {
|
||||
return NO;
|
||||
}
|
||||
AMapMarker* marker = _markerDict[markerId];
|
||||
if (!marker) {
|
||||
return NO;
|
||||
}
|
||||
[_methodChannel invokeMethod:@"marker#onDragEnd"
|
||||
arguments:@{@"markerId" : markerId, @"position" : [AMapConvertUtil jsonArrayFromCoordinate:position]}];
|
||||
return YES;
|
||||
}
|
||||
|
||||
//- (BOOL)onInfoWindowTap:(NSString *)markerId {
|
||||
// if (!markerId) {
|
||||
// return NO;
|
||||
// }
|
||||
// AMapMarker* marker = _markerDict[markerId];
|
||||
// if (!marker) {
|
||||
// return NO;
|
||||
// }
|
||||
// [_methodChannel invokeMethod:@"infoWindow#onTap" arguments:@{@"markerId" : markerId}];
|
||||
// return YES;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
@end
|
33
ios/Classes/OverlayController/AMapPolygonController.h
Normal file
33
ios/Classes/OverlayController/AMapPolygonController.h
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// AMapPolygonController.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Flutter/Flutter.h>
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AMapPolyline;
|
||||
@class AMapPolygon;
|
||||
|
||||
@interface AMapPolygonController : NSObject
|
||||
|
||||
- (instancetype)init:(FlutterMethodChannel*)methodChannel
|
||||
mapView:(MAMapView*)mapView
|
||||
registrar:(NSObject<FlutterPluginRegistrar>*)registrar;
|
||||
|
||||
- (nullable AMapPolygon *)polygonForId:(NSString *)polygonId;
|
||||
|
||||
- (void)addPolygons:(NSArray*)polygonsToAdd;
|
||||
|
||||
- (void)changePolygons:(NSArray*)polygonsToChange;
|
||||
|
||||
- (void)removePolygonIds:(NSArray*)polygonIdsToRemove;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
99
ios/Classes/OverlayController/AMapPolygonController.m
Normal file
99
ios/Classes/OverlayController/AMapPolygonController.m
Normal file
@ -0,0 +1,99 @@
|
||||
//
|
||||
// AMapPolygonController.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/12.
|
||||
//
|
||||
|
||||
#import "AMapPolygonController.h"
|
||||
#import "AMapPolygon.h"
|
||||
#import "AMapJsonUtils.h"
|
||||
#import "MAPolygon+Flutter.h"
|
||||
#import "MAPolygonRenderer+Flutter.h"
|
||||
#import "FlutterMethodChannel+MethodCallDispatch.h"
|
||||
|
||||
@interface AMapPolygonController ()
|
||||
|
||||
@property (nonatomic,strong) NSMutableDictionary<NSString*,AMapPolygon*> *polygonDict;
|
||||
@property (nonatomic,strong) FlutterMethodChannel *methodChannel;
|
||||
@property (nonatomic,strong) NSObject<FlutterPluginRegistrar> *registrar;
|
||||
@property (nonatomic,strong) MAMapView *mapView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation AMapPolygonController
|
||||
|
||||
- (instancetype)init:(FlutterMethodChannel*)methodChannel
|
||||
mapView:(MAMapView*)mapView
|
||||
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_methodChannel = methodChannel;
|
||||
_mapView = mapView;
|
||||
_polygonDict = [NSMutableDictionary dictionaryWithCapacity:1];
|
||||
_registrar = registrar;
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[_methodChannel addMethodName:@"polygons#update" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
id polygonsToAdd = call.arguments[@"polygonsToAdd"];
|
||||
if ([polygonsToAdd isKindOfClass:[NSArray class]]) {
|
||||
[weakSelf addPolygons:polygonsToAdd];
|
||||
}
|
||||
id polygonsToChange = call.arguments[@"polygonsToChange"];
|
||||
if ([polygonsToChange isKindOfClass:[NSArray class]]) {
|
||||
[weakSelf changePolygons:polygonsToChange];
|
||||
}
|
||||
id polygonIdsToRemove = call.arguments[@"polygonIdsToRemove"];
|
||||
if ([polygonIdsToRemove isKindOfClass:[NSArray class]]) {
|
||||
[weakSelf removePolygonIds:polygonIdsToRemove];
|
||||
}
|
||||
result(nil);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable AMapPolygon *)polygonForId:(NSString *)polygonId {
|
||||
return _polygonDict[polygonId];
|
||||
}
|
||||
|
||||
- (void)addPolygons:(NSArray*)polygonsToAdd {
|
||||
for (NSDictionary* polygonDict in polygonsToAdd) {
|
||||
AMapPolygon *polygon = [AMapJsonUtils modelFromDict:polygonDict modelClass:[AMapPolygon class]];
|
||||
// 先加入到字段中,避免后续的地图回到里,取不到对应的overlay数据
|
||||
if (polygon.id_) {
|
||||
_polygonDict[polygon.id_] = polygon;
|
||||
}
|
||||
[self.mapView addOverlay:polygon.polygon];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)changePolygons:(NSArray*)polygonsToChange {
|
||||
for (NSDictionary* polygonDict in polygonsToChange) {
|
||||
AMapPolygon *polygon = [AMapJsonUtils modelFromDict:polygonDict modelClass:[AMapPolygon class]];
|
||||
AMapPolygon *currentPolygon = _polygonDict[polygon.id_];
|
||||
NSAssert(currentPolygon != nil, @"需要修改的Polygon不存在");
|
||||
[currentPolygon updatePolygon:polygon];
|
||||
MAOverlayRenderer *render = [self.mapView rendererForOverlay:currentPolygon.polygon];
|
||||
if (render && [render isKindOfClass:[MAPolygonRenderer class]]) { // render没有复用,只要添加过,就一定可以获取到
|
||||
[(MAPolygonRenderer *)render updateRenderWithPolygon:currentPolygon];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removePolygonIds:(NSArray*)polygonIdsToRemove {
|
||||
for (NSString* polygonId in polygonIdsToRemove) {
|
||||
if (!polygonId) {
|
||||
continue;
|
||||
}
|
||||
AMapPolygon* polygon = _polygonDict[polygonId];
|
||||
if (!polygon) {
|
||||
continue;
|
||||
}
|
||||
[self.mapView removeOverlay:polygon.polygon];
|
||||
[_polygonDict removeObjectForKey:polygonId];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
34
ios/Classes/OverlayController/AMapPolylineController.h
Normal file
34
ios/Classes/OverlayController/AMapPolylineController.h
Normal file
@ -0,0 +1,34 @@
|
||||
//
|
||||
// AMapPolylineController.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/6.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Flutter/Flutter.h>
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class AMapPolyline;
|
||||
|
||||
@interface AMapPolylineController : NSObject
|
||||
|
||||
- (instancetype)init:(FlutterMethodChannel*)methodChannel
|
||||
mapView:(MAMapView*)mapView
|
||||
registrar:(NSObject<FlutterPluginRegistrar>*)registrar;
|
||||
|
||||
- (nullable AMapPolyline *)polylineForId:(NSString *)polylineId;
|
||||
|
||||
- (void)addPolylines:(NSArray*)polylinesToAdd;
|
||||
|
||||
- (void)changePolylines:(NSArray*)polylinesToChange;
|
||||
|
||||
- (void)removePolylineIds:(NSArray*)polylineIdsToRemove;
|
||||
|
||||
- (BOOL)onPolylineTap:(NSString*)polylineId;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
125
ios/Classes/OverlayController/AMapPolylineController.m
Normal file
125
ios/Classes/OverlayController/AMapPolylineController.m
Normal file
@ -0,0 +1,125 @@
|
||||
//
|
||||
// AMapPolylineController.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/6.
|
||||
//
|
||||
|
||||
#import "AMapPolylineController.h"
|
||||
#import "AMapPolyline.h"
|
||||
#import "AMapJsonUtils.h"
|
||||
#import "AMapMarker.h"
|
||||
#import "MAPolyline+Flutter.h"
|
||||
#import "MAPolylineRenderer+Flutter.h"
|
||||
#import "AMapConvertUtil.h"
|
||||
#import "FlutterMethodChannel+MethodCallDispatch.h"
|
||||
|
||||
@interface AMapPolylineController ()
|
||||
|
||||
@property (nonatomic,strong) NSMutableDictionary<NSString*,AMapPolyline*> *polylineDict;
|
||||
@property (nonatomic,strong) FlutterMethodChannel *methodChannel;
|
||||
@property (nonatomic,strong) NSObject<FlutterPluginRegistrar> *registrar;
|
||||
@property (nonatomic,strong) MAMapView *mapView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation AMapPolylineController
|
||||
|
||||
- (instancetype)init:(FlutterMethodChannel*)methodChannel
|
||||
mapView:(MAMapView*)mapView
|
||||
registrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_methodChannel = methodChannel;
|
||||
_mapView = mapView;
|
||||
_polylineDict = [NSMutableDictionary dictionaryWithCapacity:1];
|
||||
_registrar = registrar;
|
||||
|
||||
__weak typeof(self) weakSelf = self;
|
||||
[_methodChannel addMethodName:@"polylines#update" withHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
|
||||
id polylinesToAdd = call.arguments[@"polylinesToAdd"];
|
||||
if ([polylinesToAdd isKindOfClass:[NSArray class]]) {
|
||||
[weakSelf addPolylines:polylinesToAdd];
|
||||
}
|
||||
id polylinesToChange = call.arguments[@"polylinesToChange"];
|
||||
if ([polylinesToChange isKindOfClass:[NSArray class]]) {
|
||||
[weakSelf changePolylines:polylinesToChange];
|
||||
}
|
||||
id polylineIdsToRemove = call.arguments[@"polylineIdsToRemove"];
|
||||
if ([polylineIdsToRemove isKindOfClass:[NSArray class]]) {
|
||||
[weakSelf removePolylineIds:polylineIdsToRemove];
|
||||
}
|
||||
result(nil);
|
||||
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (nullable AMapPolyline *)polylineForId:(NSString *)polylineId {
|
||||
return _polylineDict[polylineId];
|
||||
}
|
||||
|
||||
- (void)addPolylines:(NSArray*)polylinesToAdd {
|
||||
for (NSDictionary* polyline in polylinesToAdd) {
|
||||
AMapPolyline *polylineModel = [AMapJsonUtils modelFromDict:polyline modelClass:[AMapPolyline class]];
|
||||
if (polylineModel.customTexture) {
|
||||
polylineModel.strokeImage = [AMapConvertUtil imageFromRegistrar:self.registrar iconData:polylineModel.customTexture];
|
||||
}
|
||||
// 先加入到字段中,避免后续的地图回到里,取不到对应的overlay数据
|
||||
if (polylineModel.id_) {
|
||||
_polylineDict[polylineModel.id_] = polylineModel;
|
||||
}
|
||||
[self.mapView addOverlay:polylineModel.polyline];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)changePolylines:(NSArray*)polylinesToChange {
|
||||
for (NSDictionary* polylineToChange in polylinesToChange) {
|
||||
AMapPolyline *polyline = [AMapJsonUtils modelFromDict:polylineToChange modelClass:[AMapPolyline class]];
|
||||
AMapPolyline *currentPolyline = _polylineDict[polyline.id_];
|
||||
NSAssert(currentPolyline != nil, @"需要修改的Polyline不存在");
|
||||
// 如果图片纹理变了,则存储和解析新的图标
|
||||
if ([AMapConvertUtil checkIconDescriptionChangedFrom:currentPolyline.customTexture to:polyline.customTexture]) {
|
||||
currentPolyline.strokeImage = [AMapConvertUtil imageFromRegistrar:self.registrar iconData:polyline.customTexture];
|
||||
currentPolyline.customTexture = polyline.customTexture;
|
||||
}
|
||||
//更新除了图标之外的其它信息
|
||||
[currentPolyline updatePolyline:polyline];
|
||||
MAOverlayRenderer *render = [self.mapView rendererForOverlay:currentPolyline.polyline];
|
||||
if (render && [render isKindOfClass:[MAPolylineRenderer class]]) { // render没有复用,只要添加过,就一定可以获取到
|
||||
[(MAPolylineRenderer *)render updateRenderWithPolyline:currentPolyline];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removePolylineIds:(NSArray*)polylineIdsToRemove {
|
||||
for (NSString* polylineId in polylineIdsToRemove) {
|
||||
if (!polylineId) {
|
||||
continue;
|
||||
}
|
||||
AMapPolyline* polyline = _polylineDict[polylineId];
|
||||
if (!polyline) {
|
||||
continue;
|
||||
}
|
||||
[self.mapView removeOverlay:polyline.polyline];
|
||||
[_polylineDict removeObjectForKey:polylineId];
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: Marker的回调
|
||||
|
||||
- (BOOL)onPolylineTap:(NSString*)polylineId {
|
||||
if (!polylineId) {
|
||||
return NO;
|
||||
}
|
||||
AMapPolyline* polyline = _polylineDict[polylineId];
|
||||
if (!polyline) {
|
||||
return NO;
|
||||
}
|
||||
[_methodChannel invokeMethod:@"polyline#onTap" arguments:@{@"polylineId" : polylineId}];
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
68
ios/Classes/Util/AMapConvertUtil.h
Normal file
68
ios/Classes/Util/AMapConvertUtil.h
Normal file
@ -0,0 +1,68 @@
|
||||
//
|
||||
// AMapConvertUtil.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/10/30.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import <Flutter/Flutter.h>
|
||||
#import <MAMapKit/MAMapKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class MATouchPoi;
|
||||
|
||||
@interface AMapConvertUtil : NSObject
|
||||
|
||||
/// 经纬度坐标转字符串
|
||||
/// @param coordinate 经纬度坐标
|
||||
+ (NSString *)stringFromCoordinate:(CLLocationCoordinate2D)coordinate;
|
||||
|
||||
/// 颜色的色值解析(色值必须为json中的number类型)
|
||||
/// @param numberColor 色值
|
||||
+ (UIColor*)colorFromNumber:(NSNumber*)numberColor;
|
||||
|
||||
/// 将数组(内含数字)转换为point坐标,(默认数组第一个元素为x值,第二个为y值)
|
||||
/// @param data 数组
|
||||
+ (CGPoint)pointFromArray:(NSArray*)data;
|
||||
|
||||
/// 从数据中解析经纬度
|
||||
/// @param array 经纬度数组对(默认第一个当做维度,第二个当做经度)
|
||||
+ (CLLocationCoordinate2D)coordinateFromArray:(NSArray *)array;
|
||||
|
||||
/// 经纬度转json数组
|
||||
/// @param coord 经纬度
|
||||
+ (NSArray *)jsonFromCoordinate:(CLLocationCoordinate2D )coord;
|
||||
|
||||
/// 经纬度转json数组
|
||||
/// @param coordinate 经纬度
|
||||
+ (NSArray<NSNumber *> *)jsonArrayFromCoordinate:(CLLocationCoordinate2D)coordinate;
|
||||
|
||||
+ (UIImage*)imageFromRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar iconData:(NSArray*)iconData;
|
||||
|
||||
|
||||
/// 检测图标相关的描述,是否修改过
|
||||
/// @param previousIcon 之前的图标
|
||||
/// @param currentIcon 当前新的图标
|
||||
/// @return 修改了,则返回yes,否则返回NO
|
||||
+ (BOOL)checkIconDescriptionChangedFrom:(NSArray *)previousIcon to:(NSArray *)currentIcon;
|
||||
|
||||
|
||||
/// 经纬度坐标比较
|
||||
/// @param coord1 坐标1
|
||||
/// @param coord2 坐标2
|
||||
+ (BOOL)isEqualWith:(CLLocationCoordinate2D)coord1 to:(CLLocationCoordinate2D)coord2;
|
||||
|
||||
/// TouchPOI转字典
|
||||
/// @param poi 点击POI
|
||||
+ (NSDictionary *)dictFromTouchPOI:(MATouchPoi *)poi;
|
||||
|
||||
/// 解析得到mapRect结构
|
||||
/// @param array json数组[southwest,northeast],分别为西南、东北的坐标
|
||||
+ (MAMapRect)mapRectFromArray:(NSArray *)array;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
215
ios/Classes/Util/AMapConvertUtil.m
Normal file
215
ios/Classes/Util/AMapConvertUtil.m
Normal file
@ -0,0 +1,215 @@
|
||||
//
|
||||
// AMapConvertUtil.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/10/30.
|
||||
//
|
||||
|
||||
#import "AMapConvertUtil.h"
|
||||
|
||||
@implementation AMapConvertUtil
|
||||
|
||||
|
||||
/// 经纬度坐标转字符串
|
||||
/// @param coordinate 经纬度坐标
|
||||
+ (NSString *)stringFromCoordinate:(CLLocationCoordinate2D)coordinate {
|
||||
return [NSString stringWithFormat:@"{%.6f,%.6f}", coordinate.longitude, coordinate.latitude];
|
||||
}
|
||||
|
||||
+ (UIColor*)colorFromNumber:(NSNumber*)numberColor {
|
||||
if (numberColor == nil || [numberColor isKindOfClass:[NSNumber class]] == NO) {
|
||||
return nil;
|
||||
}
|
||||
unsigned long value = [numberColor unsignedLongValue];
|
||||
return [UIColor colorWithRed:((float)((value & 0xFF0000) >> 16)) / 255.0
|
||||
green:((float)((value & 0xFF00) >> 8)) / 255.0
|
||||
blue:((float)(value & 0xFF)) / 255.0
|
||||
alpha:((float)((value & 0xFF000000) >> 24)) / 255.0];
|
||||
}
|
||||
|
||||
+ (CGPoint)pointFromArray:(NSArray*)data {
|
||||
NSAssert((data != nil && [data isKindOfClass:[NSArray class]] && data.count == 2), @"数组类型转point格式错误");
|
||||
return CGPointMake([data[0] doubleValue],
|
||||
[data[1] doubleValue]);
|
||||
}
|
||||
|
||||
/// 从数据中解析经纬度
|
||||
/// @param array 经纬度数组对(默认第一个当做维度,第二个当做经度)
|
||||
+ (CLLocationCoordinate2D)coordinateFromArray:(NSArray *)array {
|
||||
CLLocationCoordinate2D location = kCLLocationCoordinate2DInvalid;
|
||||
if (array.count == 2) {
|
||||
double latitude = [array[0] doubleValue];
|
||||
double longitude = [array[1] doubleValue];
|
||||
if ([self checkValidLatitude:latitude longitude:longitude]) {
|
||||
location = CLLocationCoordinate2DMake(latitude, longitude);
|
||||
} else if ([self checkValidLatitude:longitude longitude:latitude]) {//交换二者
|
||||
location = CLLocationCoordinate2DMake(longitude, latitude);
|
||||
} else {
|
||||
NSLog(@"经纬度参数异常,解析为无效经纬度");
|
||||
}
|
||||
} else {
|
||||
NSLog(@"经纬度参数异常,解析为无效经纬度");
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
+ (NSArray *)jsonFromCoordinate:(CLLocationCoordinate2D )coord {
|
||||
if (CLLocationCoordinate2DIsValid(coord)) {
|
||||
return @[@(coord.latitude),@(coord.longitude)];
|
||||
} else {
|
||||
NSLog(@"经纬度无效,返回为空");
|
||||
return @[];
|
||||
}
|
||||
}
|
||||
|
||||
/// 检测经纬度是否有效
|
||||
/// @param latitude 维度
|
||||
/// @param longitude 经度
|
||||
+ (BOOL)checkValidLatitude:(double)latitude longitude:(double)longitude {
|
||||
if (latitude > 90 || latitude < -90) {
|
||||
return false;
|
||||
}
|
||||
if (longitude > 180 || longitude < -180) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+ (NSArray<NSNumber *> *)jsonArrayFromCoordinate:(CLLocationCoordinate2D)coordinate {
|
||||
if (CLLocationCoordinate2DIsValid(coordinate)) {
|
||||
return @[ @(coordinate.latitude), @(coordinate.longitude) ];
|
||||
} else {
|
||||
return @[];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ (UIImage*)scaleImage:(UIImage*)image param:(NSNumber*)scaleParam {
|
||||
double scale = 1.0;
|
||||
if ([scaleParam isKindOfClass:[NSNumber class]]) {
|
||||
scale = scaleParam.doubleValue;
|
||||
}
|
||||
if (fabs(scale - 1) > 1e-3) {
|
||||
return [UIImage imageWithCGImage:[image CGImage]
|
||||
scale:(image.scale * scale)
|
||||
orientation:(image.imageOrientation)];
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
+ (UIImage*)imageFromRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar iconData:(NSArray*)iconData {
|
||||
UIImage* image;
|
||||
if ([iconData.firstObject isEqualToString:@"defaultMarker"]) {
|
||||
image = [UIImage imageNamed:[registrar lookupKeyForAsset:@"packages/amap_map/res/marker_default.png"]];//默认的图片资源
|
||||
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
||||
image = [self scaleImage:image param:[NSNumber numberWithFloat:screenScale]];
|
||||
//添加默认图片
|
||||
} else if ([iconData.firstObject isEqualToString:@"fromAsset"]) {
|
||||
if (iconData.count == 2) {
|
||||
image = [UIImage imageNamed:[registrar lookupKeyForAsset:iconData[1]]];
|
||||
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
||||
image = [self scaleImage:image param:[NSNumber numberWithFloat:screenScale]];
|
||||
}
|
||||
} else if ([iconData.firstObject isEqualToString:@"fromAssetImage"]) {
|
||||
if (iconData.count == 3) {
|
||||
image = [UIImage imageNamed:[registrar lookupKeyForAsset:iconData[1]]];
|
||||
NSNumber* scaleParam = iconData[2];
|
||||
image = [self scaleImage:image param:scaleParam];
|
||||
} else {
|
||||
NSString* error =
|
||||
[NSString stringWithFormat:@"'fromAssetImage' should have exactly 3 arguments. Got: %lu",
|
||||
(unsigned long)iconData.count];
|
||||
NSException* exception = [NSException exceptionWithName:@"InvalidBitmapDescriptor"
|
||||
reason:error
|
||||
userInfo:nil];
|
||||
@throw exception;
|
||||
}
|
||||
} else if ([iconData[0] isEqualToString:@"fromBytes"]) {
|
||||
if (iconData.count == 2) {
|
||||
@try {
|
||||
FlutterStandardTypedData* byteData = iconData[1];
|
||||
CGFloat screenScale = [[UIScreen mainScreen] scale];
|
||||
image = [UIImage imageWithData:[byteData data] scale:screenScale];
|
||||
} @catch (NSException* exception) {
|
||||
@throw [NSException exceptionWithName:@"InvalidByteDescriptor"
|
||||
reason:@"Unable to interpret bytes as a valid image."
|
||||
userInfo:nil];
|
||||
}
|
||||
} else {
|
||||
NSString* error = [NSString
|
||||
stringWithFormat:@"fromBytes should have exactly one argument, the bytes. Got: %lu",
|
||||
(unsigned long)iconData.count];
|
||||
NSException* exception = [NSException exceptionWithName:@"InvalidByteDescriptor"
|
||||
reason:error
|
||||
userInfo:nil];
|
||||
@throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/// 检测图标相关的描述,是否修改过
|
||||
/// @param previousIcon 之前的图标
|
||||
/// @param currentIcon 当前新的图标
|
||||
/// @return 修改了,则返回yes,否则返回NO
|
||||
+ (BOOL)checkIconDescriptionChangedFrom:(NSArray *)previousIcon to:(NSArray *)currentIcon {
|
||||
if (previousIcon.count != currentIcon.count) {
|
||||
return YES;
|
||||
}
|
||||
//两个数组的数量一样
|
||||
for (NSUInteger index = 0; index < previousIcon.count; index ++) {
|
||||
if ([previousIcon[index] isKindOfClass:[NSString class]]) {
|
||||
if ([previousIcon[index] isEqualToString:currentIcon[index]] == NO) {
|
||||
return YES;
|
||||
}
|
||||
} else if ([previousIcon[index] isKindOfClass:[NSNumber class]]) {
|
||||
if (fabs([previousIcon[index] doubleValue] - [currentIcon[index] doubleValue]) > 0.000001) {
|
||||
return YES;
|
||||
}
|
||||
} else {//其它数据无法比较,直接默认强制更新
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (BOOL)isEqualWith:(CLLocationCoordinate2D)coord1 to:(CLLocationCoordinate2D)coord2 {
|
||||
if (fabs(coord1.latitude - coord2.latitude) > 0.000001 || fabs(coord1.longitude - coord2.longitude) > 0.000001) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSDictionary *)dictFromTouchPOI:(MATouchPoi *)poi {
|
||||
if (poi == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:3];
|
||||
if (poi.name) {
|
||||
[dict setObject:poi.name forKey:@"name"];
|
||||
}
|
||||
if (CLLocationCoordinate2DIsValid(poi.coordinate)) {
|
||||
[dict setObject:[AMapConvertUtil jsonArrayFromCoordinate:poi.coordinate] forKey:@"latLng"];
|
||||
}
|
||||
if (poi.uid) {
|
||||
[dict setObject:poi.uid forKey:@"id"];
|
||||
}
|
||||
return [dict copy];
|
||||
}
|
||||
|
||||
+ (MAMapRect)mapRectFromArray:(NSArray *)array {
|
||||
NSAssert((array && [array isKindOfClass:[NSArray class]] && array.count == 2), @"解析mapRect的参数有误");
|
||||
CLLocationCoordinate2D southwest = [AMapConvertUtil coordinateFromArray:array[0]];
|
||||
CLLocationCoordinate2D northeast = [AMapConvertUtil coordinateFromArray:array[1]];
|
||||
MAMapPoint mapNorthEastPoint = MAMapPointForCoordinate(northeast);
|
||||
MAMapPoint mapSouthWestPoint = MAMapPointForCoordinate(southwest);
|
||||
double width = fabs(mapNorthEastPoint.x - mapSouthWestPoint.x);
|
||||
double height = fabs(mapNorthEastPoint.y - mapSouthWestPoint.y);
|
||||
MAMapRect limitRect = MAMapRectMake(mapSouthWestPoint.x, mapNorthEastPoint.y, width, height);
|
||||
return limitRect;
|
||||
}
|
||||
|
||||
|
||||
@end
|
35
ios/Classes/Util/AMapJsonUtils.h
Normal file
35
ios/Classes/Util/AMapJsonUtils.h
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// MAJsonUtils.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by shaobin on 2019/2/13.
|
||||
// Copyright © 2019 Amap.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AMapJsonUtils : NSObject
|
||||
|
||||
/**
|
||||
model转为可序列化为json的对象。
|
||||
|
||||
@param model model对象:支持NSDictionary、NSArray、自定义类,且支持嵌套(Dict、Array内包含自定义类示例,或自定义类内包含Dict、Array) 注意如果自定义类或dict、array中包含非字符串、数字、布尔、null类型的属性,其行为是undefined的
|
||||
@return 返回NSArray或者NSDictionary对象,如果失败返回nil。
|
||||
*/
|
||||
+ (id)jsonObjectFromModel:(id)model;
|
||||
|
||||
/**
|
||||
dict转model
|
||||
|
||||
@param dict dict
|
||||
@param modelClass model对应的Class
|
||||
@return 返回modelClass实例
|
||||
*/
|
||||
+ (id)modelFromDict:(NSDictionary*)dict modelClass:(Class)modelClass;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
275
ios/Classes/Util/AMapJsonUtils.m
Normal file
275
ios/Classes/Util/AMapJsonUtils.m
Normal file
@ -0,0 +1,275 @@
|
||||
//
|
||||
// MAJsonUtils.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by shaobin on 2019/2/13.
|
||||
// Copyright © 2019 Amap.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AMapJsonUtils.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import "AMapConvertUtil.h"
|
||||
|
||||
@implementation AMapJsonUtils
|
||||
|
||||
+ (BOOL)isValidJsonValue:(id)value {
|
||||
if([value isKindOfClass:NSString.class] ||
|
||||
[value isKindOfClass:NSNumber.class] ||
|
||||
value == [NSNull null]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
+ (id)jsonValueFromObject:(id)obj {
|
||||
if([self isValidJsonValue:obj]) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if(!obj) {
|
||||
return [NSNull null];
|
||||
}
|
||||
|
||||
//常用基本类型判断,not exhausted
|
||||
if([obj isKindOfClass:NSDate.class] ||
|
||||
[obj isKindOfClass:NSData.class] ||
|
||||
[obj isKindOfClass:NSValue.class]) {
|
||||
NSString *retStr = [NSString stringWithFormat:@"%@", obj];
|
||||
return retStr;
|
||||
}
|
||||
|
||||
if([obj isKindOfClass:NSArray.class]) {
|
||||
NSArray *oldArray = (NSArray*)obj;
|
||||
NSMutableArray *retArray = [NSMutableArray arrayWithCapacity:[oldArray count]];
|
||||
for(id item in oldArray) {
|
||||
id jsonValue = [self jsonValueFromObject:item];
|
||||
[retArray addObject:jsonValue];
|
||||
}
|
||||
return retArray;
|
||||
}
|
||||
|
||||
if([obj isKindOfClass:NSDictionary.class]) {
|
||||
NSDictionary *oldDict = (NSDictionary *)obj;
|
||||
NSMutableDictionary *retDict = [NSMutableDictionary dictionaryWithCapacity:[oldDict count]];
|
||||
for(id key in [oldDict allKeys]) {
|
||||
id item = [oldDict objectForKey:key];
|
||||
id jsonValue = [self jsonValueFromObject:item];
|
||||
if(jsonValue) {
|
||||
[retDict setObject:jsonValue forKey:key];
|
||||
}
|
||||
}
|
||||
return retDict;
|
||||
}
|
||||
|
||||
NSArray *propertyArray = [self allPropertiesOfClass:[obj class]];
|
||||
NSMutableDictionary *returnDict = [NSMutableDictionary dictionaryWithCapacity:propertyArray.count];
|
||||
for(NSString *property in propertyArray) {
|
||||
id value = [obj valueForKey:property];
|
||||
if(value) {
|
||||
id jsonValue = [self jsonValueFromObject:value];
|
||||
NSString *mappedName = property;
|
||||
if(jsonValue) {
|
||||
[returnDict setObject:jsonValue forKey:mappedName];
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnDict;
|
||||
}
|
||||
|
||||
+ (id)jsonObjectFromModel:(id)model {
|
||||
id ret = [self jsonValueFromObject:model];
|
||||
if(![NSJSONSerialization isValidJSONObject:ret]) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ (id)modelFromDict:(NSDictionary*)dict modelClass:(Class)modelClass {
|
||||
if(![dict isKindOfClass:[NSDictionary class]]) {
|
||||
NSLog(@"[AMap] the object must be of %@", [NSDictionary class]);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if([modelClass isSubclassOfClass:[NSDictionary class]]) {
|
||||
return [dict copy];
|
||||
}
|
||||
|
||||
//获取clazz属性列表
|
||||
NSArray *propertyArray = [self allPropertiesOfClass:modelClass];
|
||||
NSMutableArray* missedProperties = [NSMutableArray array];
|
||||
id ret = [[modelClass alloc] init];
|
||||
//枚举clazz中的每个属性,然后赋值
|
||||
for (NSString *propertyName in propertyArray) {
|
||||
NSString *keyName = propertyName;
|
||||
id value = [dict objectForKey:keyName];
|
||||
//'id'是关键字,服务端返回'id'字段属性名更改为'id_'
|
||||
if(!value && [propertyName isEqualToString:@"id_"]) {
|
||||
value = [dict objectForKey:@"id"];
|
||||
}
|
||||
if(!value) {
|
||||
[missedProperties addObject:propertyName];
|
||||
continue;
|
||||
}
|
||||
|
||||
if(value == [NSNull null]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Class propertyClass = nil;
|
||||
objc_property_t property = class_getProperty(modelClass, [propertyName UTF8String]);
|
||||
NSString *propertyAttributes = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
|
||||
NSArray *splitPropertyAttributes = [propertyAttributes componentsSeparatedByString:@","];
|
||||
if(splitPropertyAttributes.count > 0) {
|
||||
NSString *encodeType = splitPropertyAttributes[0];
|
||||
if([encodeType hasPrefix:@"T@"]) {
|
||||
NSArray *splitEncodeType = [encodeType componentsSeparatedByString:@"\""];
|
||||
NSString *className = nil;
|
||||
if(splitEncodeType.count > 1) {
|
||||
className = splitEncodeType[1];
|
||||
}
|
||||
if(className) {
|
||||
propertyClass = NSClassFromString(className);
|
||||
}
|
||||
} else if ([encodeType isEqualToString:@"T{CLLocationCoordinate2D=dd}"]) {//经纬度
|
||||
//解析经纬度
|
||||
CLLocationCoordinate2D coordinate = [self coordinateFromModel:value];
|
||||
//使用msgSend直接设置经纬度的属性
|
||||
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]);
|
||||
((void (*)(id,SEL,CLLocationCoordinate2D))objc_msgSend)(ret,sel,coordinate);
|
||||
continue;
|
||||
} else if ([encodeType isEqualToString:@"T{CGPoint=dd}"]) {//CGPoint点
|
||||
CGPoint point = [AMapConvertUtil pointFromArray:value];
|
||||
//使用msgSend直接设置经纬度的属性
|
||||
SEL sel = NSSelectorFromString([NSString stringWithFormat:@"set%@:",[propertyName capitalizedString]]);
|
||||
((void (*)(id,SEL,CGPoint))objc_msgSend)(ret,sel,point);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
//获取property类型后,再处理
|
||||
if(propertyClass) {
|
||||
if([value isKindOfClass:propertyClass]) {
|
||||
//array 需要特殊处理
|
||||
if([propertyClass isSubclassOfClass:NSArray.class]) {
|
||||
NSString *elementClassSel = [NSString stringWithFormat:@"%@ElementClass", propertyName];
|
||||
SEL selector = NSSelectorFromString(elementClassSel);
|
||||
if([[ret class] respondsToSelector:selector]) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
Class elementCls = [[ret class] performSelector:selector];
|
||||
#pragma clang diagnostic pop
|
||||
NSArray *arr = (NSArray *)value;
|
||||
NSMutableArray *mutArr = [NSMutableArray arrayWithCapacity:arr.count];
|
||||
for(id item in arr) {
|
||||
id newItem = [self modelFromDict:item modelClass:elementCls];
|
||||
if(newItem) {
|
||||
[mutArr addObject:newItem];
|
||||
} else {
|
||||
[mutArr addObject:item];
|
||||
}
|
||||
}
|
||||
[ret setValue:mutArr forKey:propertyName];
|
||||
} else {
|
||||
[ret setValue:value forKey:propertyName];
|
||||
}
|
||||
} else {
|
||||
[ret setValue:value forKey:propertyName];
|
||||
}
|
||||
} else if([value isKindOfClass:NSDictionary.class]){
|
||||
NSDictionary *tempDic = value;
|
||||
id model = [self modelFromDict:tempDic modelClass:propertyClass];
|
||||
[ret setValue:model forKey:propertyName];
|
||||
} else if ([value isKindOfClass:[NSNumber class]] && [NSStringFromClass(propertyClass) isEqualToString:@"UIColor"]) {
|
||||
UIColor *color = [AMapConvertUtil colorFromNumber:value];
|
||||
[ret setValue:color forKey:propertyName];
|
||||
} else {
|
||||
[ret setValue:value forKey:propertyName];
|
||||
#ifdef DEBUG
|
||||
Class valueClaz = [value class];
|
||||
NSLog(@"\U0001F913\U0001F913 Warning1: property '%@' of %@ is %@, %@ is received", propertyName, modelClass, propertyClass, valueClaz);
|
||||
#endif
|
||||
}
|
||||
} else { //end of if(propertyClaz) 如@"Ti" @"Tf"
|
||||
if([self isValidJsonValue:value]){
|
||||
[ret setValue:value forKey:propertyName];
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
Class valueClaz = [value class];
|
||||
NSLog(@"\U0001F913\U0001F913 Warning1: property '%@' of %@ is %@, %@ is received", propertyName, modelClass, propertyClass, valueClaz);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if([missedProperties count] > 0) {
|
||||
NSLog(@"\U0001F913\U0001F913 Warning2: %@ value missed: %@", modelClass, missedProperties);
|
||||
}
|
||||
#endif
|
||||
|
||||
NSString *postHookSel = [NSString stringWithFormat:@"postHookWith:"];
|
||||
SEL sel = NSSelectorFromString(postHookSel);
|
||||
if([ret respondsToSelector:sel]) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
|
||||
[ret performSelector:sel withObject:dict];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//返回array of propertyNames
|
||||
+ (NSArray<NSString*> *)allPropertiesOfClass:(Class)cls {
|
||||
Class clazz = cls;
|
||||
|
||||
NSMutableArray *mutArr = [[NSMutableArray alloc] init];
|
||||
while(clazz != [NSObject class]) {
|
||||
unsigned int count = 0;
|
||||
objc_property_t* properties = class_copyPropertyList(clazz, &count);
|
||||
|
||||
for (int i = 0; i < count ; i++) {
|
||||
objc_property_t prop = properties[i];
|
||||
NSString *propertyName = [NSString stringWithCString:property_getName(prop) encoding:NSUTF8StringEncoding];
|
||||
[mutArr addObject:propertyName];
|
||||
}
|
||||
|
||||
if(properties) {
|
||||
free(properties);
|
||||
}
|
||||
|
||||
clazz = class_getSuperclass(clazz);
|
||||
}
|
||||
|
||||
return mutArr;
|
||||
}
|
||||
|
||||
|
||||
//从数据model中解析经纬度
|
||||
+ (CLLocationCoordinate2D)coordinateFromModel:(id)model {
|
||||
CLLocationCoordinate2D location = kCLLocationCoordinate2DInvalid;
|
||||
if ([model isKindOfClass:[NSArray class]]) {
|
||||
return [AMapConvertUtil coordinateFromArray:model];
|
||||
} else if ([model isKindOfClass:[NSString class]]) {//后台经纬度字符串习惯是(经度,维度)的格式
|
||||
NSString *coordStr = model;
|
||||
NSArray *array = [coordStr componentsSeparatedByString:@","];
|
||||
array = [[array reverseObjectEnumerator] allObjects];//这里需要逆置
|
||||
return [AMapConvertUtil coordinateFromArray:array];
|
||||
} else if ([model isKindOfClass:[NSDictionary class]]) {
|
||||
NSDictionary *dict = model;
|
||||
NSNumber *latitudeNum = [dict objectForKey:@"latitude"];
|
||||
NSNumber *longitudeNum = [dict objectForKey:@"longitude"];
|
||||
if (latitudeNum && longitudeNum) {
|
||||
location = CLLocationCoordinate2DMake([latitudeNum doubleValue], [longitudeNum doubleValue]);
|
||||
} else {
|
||||
NSLog(@"经纬度参数异常,解析为无效经纬度");
|
||||
}
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
@end
|
27
ios/Classes/Util/AMapMethodCallDispatcher.h
Normal file
27
ios/Classes/Util/AMapMethodCallDispatcher.h
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// AMapMethodCallDispatcher.h
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/16.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Flutter/Flutter.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// methodCall的分发器,该对象以Category的形式设置给FlutterMethodChannel,作为FlutterMethodCallHandler,
|
||||
/// 再根据call.method来分发处理对应的处理block
|
||||
@interface AMapMethodCallDispatcher : NSObject
|
||||
|
||||
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
|
||||
|
||||
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler;
|
||||
|
||||
- (void)removeHandlerWithMethodName:(NSString *)methodName;
|
||||
|
||||
- (void)clearAllHandler;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
61
ios/Classes/Util/AMapMethodCallDispatcher.m
Normal file
61
ios/Classes/Util/AMapMethodCallDispatcher.m
Normal file
@ -0,0 +1,61 @@
|
||||
//
|
||||
// AMapMethodCallDispatcher.m
|
||||
// amap_map
|
||||
//
|
||||
// Created by lly on 2020/11/16.
|
||||
//
|
||||
|
||||
#import "AMapMethodCallDispatcher.h"
|
||||
|
||||
@interface AMapMethodCallDispatcher ()
|
||||
|
||||
@property (nonatomic, strong) NSRecursiveLock *dictLock;
|
||||
|
||||
@property (nonatomic, strong) NSMutableDictionary *callDict;
|
||||
|
||||
@end
|
||||
|
||||
@implementation AMapMethodCallDispatcher
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
self.dictLock = [[NSRecursiveLock alloc] init];
|
||||
self.callDict = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
|
||||
[self.dictLock lock];
|
||||
FlutterMethodCallHandler handle = [self.callDict objectForKey:call.method];
|
||||
[self.dictLock unlock];
|
||||
if (handle) {
|
||||
handle(call,result);
|
||||
} else {
|
||||
NSLog(@"call method:%@ handler is null",call.method);
|
||||
result(nil);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addMethodName:(NSString *)methodName withHandler:(FlutterMethodCallHandler)handler {
|
||||
NSAssert((methodName.length > 0 && handler != nil), @"添加methodCall回调处理参数异常");
|
||||
[self.dictLock lock];
|
||||
[self.callDict setObject:handler forKey:methodName];
|
||||
[self.dictLock unlock];
|
||||
}
|
||||
|
||||
- (void)removeHandlerWithMethodName:(NSString *)methodName {
|
||||
NSAssert(methodName.length > 0, @"移除methodCall时,参数异常");
|
||||
[self.dictLock lock];
|
||||
[self.callDict removeObjectForKey:methodName];
|
||||
[self.dictLock unlock];
|
||||
}
|
||||
|
||||
- (void)clearAllHandler {
|
||||
[self.dictLock lock];
|
||||
[self.callDict removeAllObjects];
|
||||
[self.dictLock unlock];
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user