80

点我达weex造轮子-map地图篇

 5 years ago
source link: http://tech.dianwoda.com/2018/10/07/dian-wo-da-weexzao-lun-zi-mapdi-tu-pian/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前言:随着公司业务中采用weex技术来实现业务的场景越来越多,对于扎根在即时物流的我们来说地图功能至关重要,然而插件市场现存的地图相关的插件长期没人维护,没有降级功能,路径计算等功能不全,android跑不起等等奇葩的坑让开发者苦不堪言,我们对此进行了探索,出于老业务采用高德地图来实现android,iOS,web相关功能的背景,我们处于兼容的考虑选择了高德地图对weex进行地图相关功能进行扩展,借此机会来记录下的这个虐心的过程,希望能帮助到正在使用weex开发的小伙伴们少走些弯路。

目录

  • 1.高德地图开发准备工作
    • 1.1 iOS高德地图开发流程简单介绍
    • 1.2 android高德地图开发流程简单介绍
    • 1.3 web高德地图开发流程简单介绍
  • 2. weex-iOS地图组件扩展方式介绍
    • 2.1 dwd-weex-amap
    • 2.2 dwd-weex-amap-marker
    • 2.3 dwd-weex-amap-info-window
    • 2.4 dwd-weex-amap-circle
    • 2.5 dwd-weex-amap-polygon
    • 2.5 dwd-weex-amap-polyline
  • 3.weex-android地图组件扩展方式介绍
    • 3.1 dwd-weex-amap
    • 3.2 dwd-weex-amap-marker
    • 3.3 dwd-weex-amap-info-window
    • 3.4 dwd-weex-amap-circle
    • 3.5 dwd-weex-amap-polygon
    • 3.6 dwd-weex-amap-polyline
  • 4.weex-html5地图组件扩展方式介绍
    • 4.1 dwd-weex-amap
    • 4.2 dwd-weex-amap-marker
    • 4.3 dwd-weex-amap-info-window
    • 4.4 dwd-weex-amap-circle
    • 4.5 dwd-weex-amap-polygon
    • 4.6 dwd-weex-amap-polyline
  • 5.获取地图数据(例如骑行路径规划)
    • 5.1 weex-iOS地图骑行路径规划
    • 5.2 weex-android地图骑行路径规划
    • 5.3 weex-web地图骑行路径规划

1.高德地图开发准备工作

iaMbUvv.jpg!web

  • 1.1 iOS高德地图开发流程简单介绍
1.使用 CocoaPods 安装AMapSearch,AMap3DMap SDK  
2.前往高德开放平台控制台申请 iOS Key  
3.配置高德Key至AppDelegate.m文件
  • 1.2 android高德地图开发流程简单介绍
1.使用 CocoaPods 安装AMapSearch,AMap3DMap SDK  
2.前往高德开放平台控制台申请 android Key  
3.AndroidManifest.xml的application标签中配置Key  
4.AndroidManifest.xml中配置权限
  • 1.3 HTML5高德地图开发流程简单介绍(本文采用elm封装的vue-amap作为试例)
1.前往高德开放平台控制台申请 jsAPI Key  
2.可通过CDN同步加载方式或使用require异步方式来加载key

注: 高德地图开发文档 , vue-amap开发文档

2.weex-iOS地图组件扩展方式介绍**

  • 2.1 dwd-weex-amap bEZRZrr.png!web 思路:
1. 新建DMapViewComponent类继承WXComponent  
2.在DMapViewComponent实现文件中实现MAMapViewDelegate代理  
3. 重写DMapViewComponent的loadView方法加载地图视图并设置自身为代理对象  
4.在DMapViewComponent的初始化函数viewDidLoad中做一些准备工作  
5.在DMapViewComponent的initWithRef方法中实现属性绑定  
6.通过fireEvent添加适当时机可以触发的事件  
7.重写insertSubview方法来添加子组建包括覆盖物,线,圆等等

部分代码:

@implementation DMapViewComponent
...
// 属性绑定
- (instancetype)initWithRef:(NSString *)ref
                       type:(NSString*)type
                     styles:(nullable NSDictionary *)styles
                 attributes:(nullable NSDictionary *)attributes
                     events:(nullable NSArray *)events
               weexInstance:(WXSDKInstance *)weexInstance
{
    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
    if (self) {
        // 中心点
        NSArray *center = [attributes map_safeObjectForKey:@"center"];
        _zoomLevel = [[attributes map_safeObjectForKey:@"zoom"] floatValue];
        // 是否允许显示指南针
        _compass = [[attributes map_safeObjectForKey:@"compass"] boolValue];
        // sdkKey
        if ([attributes map_safeObjectForKey:@"sdkKey"]) {
            [self setAPIKey:[attributes[@"sdkKey"] objectForKey:@"ios"] ? : @""];
        }
...
    }
    return self;
}
// 重写DMapViewComponent的loadView方法加载地图视图并设置自身为代理对象   
- (UIView *) loadView
{
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    CGSize windowSize = window.rootViewController.view.frame.size;
    self.mapView = [[MAMapView alloc] initWithFrame:CGRectMake(0, 0, windowSize.width, windowSize.height)];
    self.mapView.showsUserLocation = _showGeolocation;
    self.mapView.delegate = self;
    self.mapView.customMapStyleEnabled = YES;
    [self.mapView setCustomMapStyleWithWebData:[self getMapData]];

    return self.mapView;
}
// 设置地图样式
- (NSData *)getMapData
{
    NSString *path = [NSString stringWithFormat:@"%@/gaodeMapStyle.data", [NSBundle mainBundle].bundlePath];
    NSData *data = [NSData dataWithContentsOfFile:path];
    return data;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.mapView.showsScale = _showScale;
    self.mapView.showsCompass = _compass;
    [self.mapView setCenterCoordinate:_centerCoordinate];
    [self.mapView setZoomLevel:_zoomLevel];
}

// 添加覆盖物
- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index
{
    if ([subcomponent isKindOfClass:[DMapRenderer class]]) {
        DMapRenderer *overlayRenderer = (DMapRenderer *)subcomponent;
        [self addOverlay:overlayRenderer];
    }else if ([subcomponent isKindOfClass:[DMapViewMarkerComponent class]]) {
        [self addMarker:(DMapViewMarkerComponent *)subcomponent];
    }
}
// 更新属性
- (void)updateAttributes:(NSDictionary *)attributes
{
...
    if (attributes[@"zoom"]) {
        [self setZoomLevel:[attributes[@"zoom"] floatValue]];
    }
 ...
}
#pragma mark - component interface
- (void)setAPIKey:(NSString *)appKey
{
    [AMapServices sharedServices].apiKey = appKey;
}
- (void)setZoomLevel:(CGFloat)zoom
{
    [self.mapView setZoomLevel:zoom animated:YES];
}
#pragma mark - publish method
- (NSDictionary *)getUserLocation
{
    if(self.mapView.userLocation.updating && self.mapView.userLocation.location) {
        NSArray *coordinate = @[[NSNumber numberWithDouble:self.mapView.userLocation.location.coordinate.longitude],[NSNumber numberWithDouble:self.mapView.userLocation.location.coordinate.latitude]];
        NSDictionary *userDic = @{@"result":@"success",@"data":@{@"position":coordinate,@"title":@""}};
        return userDic;
    }
    return @{@"resuldt":@"false",@"data":@""};
}

#pragma mark - mapview delegate
/*!
 @brief 根据anntation生成对应的View
 */
- (MAAnnotationView*)mapView:(MAMapView *)mapView viewForAnnotation:(id <MAAnnotation>)annotation
{
    if ([annotation isKindOfClass:[MAPointAnnotation class]])
    {
        MAPointAnnotation *pointAnnotation = (MAPointAnnotation *)annotation;
        if ([pointAnnotation.component isKindOfClass:[WXMapInfoWindowComponent class]]) {
            return [self _generateCustomInfoWindow:mapView viewForAnnotation:pointAnnotation];

        }else {
            return [self _generateAnnotationView:mapView viewForAnnotation:pointAnnotation];
        }
    }

    return nil;
}

/**
 * @brief 当选中一个annotation views时,调用此接口
 * @param mapView 地图View
 * @param view 选中的annotation views
 */
- (void)mapView:(MAMapView *)mapView didSelectAnnotationView:(MAAnnotationView *)view
{
    MAPointAnnotation *annotation = view.annotation;
    for (WXComponent *component in self.subcomponents) {
        if ([component isKindOfClass:[WXMapViewMarkerComponent class]] &&
            [component.ref isEqualToString:annotation.component.ref]) {
            WXMapViewMarkerComponent *marker = (WXMapViewMarkerComponent *)component;
            if (marker.clickEvent) {
                [marker fireEvent:marker.clickEvent params:[NSDictionary dictionary]];
            }
        }
    }
}

/**
 * @brief 当取消选中一个annotation views时,调用此接口
 * @param mapView 地图View
 * @param view 取消选中的annotation views
 */
- (void)mapView:(MAMapView *)mapView didDeselectAnnotationView:(MAAnnotationView *)view
{

}

/**
 * @brief 地图移动结束后调用此接口
 * @param mapView       地图view
 * @param wasUserAction 标识是否是用户动作
 */
- (void)mapView:(MAMapView *)mapView mapDidMoveByUser:(BOOL)wasUserAction
{
    if (_isDragend) {
        [self fireEvent:@"dragend" params:[NSDictionary dictionary]];
    }
}

/**设置地图缩放级别 */
- (void)setMapViewRegion:(NSMutableArray *)poiArray animated:(BOOL)animated {
    NSMutableArray *arrays = [NSMutableArray array];
    for (MAPointAnnotation *anot in self.mapView.annotations) {
        CLLocationCoordinate2D coordinate = anot.coordinate;
        NSDictionary *poidic = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:coordinate.latitude * 1000000], @"lat",
                                [NSNumber numberWithInt:coordinate.longitude * 1000000], @"lng", nil];
        [arrays addObject:poidic];
    }

    MACoordinateRegion region = [self getCoordinateMapSpan:arrays];
    [self.mapView setRegion:region animated:animated];
}

/**配置地图region */
- (MACoordinateRegion)getCoordinateMapSpan:(NSMutableArray *)knightArray {
    MACoordinateRegion region;
    MACoordinateSpan span;

    CLLocationDegrees maxLat = -90;
    CLLocationDegrees maxLon = -180;
    CLLocationDegrees minLat = 90;
    CLLocationDegrees minLon = 180;

    if (knightArray && knightArray.count > 1) {
        for (int i = 0; i < knightArray.count; i++) {
            NSDictionary *knightDictionary = [knightArray objectAtIndex:i];
            float lat = [[knightDictionary objectForKey:@"lat"] floatValue] / 1000000;
            float lng = [[knightDictionary objectForKey:@"lng"] floatValue] / 1000000;

            if(lat > maxLat)
                maxLat = lat;
            if(lat < minLat)
                minLat = lat;
            if(lng > maxLon)
                maxLon = lng;
            if(lng < minLon)
                minLon = lng;
        }

        span.latitudeDelta = (maxLat - minLat) * 2 + 0.005;
        span.longitudeDelta = (maxLon - minLon) * 2 + 0.005;
        region.center.latitude = (maxLat + minLat) / 2;
        region.center.longitude = (maxLon + minLon) / 2;
        region.span = span;
    } else {
        NSDictionary *knightDictionary = [knightArray objectAtIndex:0];
        span.latitudeDelta = 0.01;
        span.longitudeDelta = 0.01;
        float lat = [[knightDictionary objectForKey:@"lat"] floatValue] / 1000000;
        float lng = [[knightDictionary objectForKey:@"lng"] floatValue] / 1000000;
        if (lat !=0 && lng != 0) {
            region.center.longitude = lng;
            region.center.latitude = lat;
        } else {
            region.center = [[ShopLocateManager shared] getLocationCoordinate];
        }
        region.span = span;
    }

    return region;
}
...
@end
  • 2.2 dwd-weex-amap-marker FJjmUz6.png!web 思路:
1. 新建DMapViewMarkerComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addAnnotation方法添加DMapViewMarkerComponent组件  
3. 在DMapViewComponent重写insertSubview方法来添加子组建覆盖物

部分代码:

- (instancetype)initWithRef:(NSString *)ref
                       type:(NSString*)type
                     styles:(nullable NSDictionary *)styles
                 attributes:(nullable NSDictionary *)attributes
                     events:(nullable NSArray *)events
               weexInstance:(WXSDKInstance *)weexInstance
{
    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
    if (self) {
        if ([events containsObject:@"click"]) {
            _clickEvent = @"click";
        }
        NSArray *offset = attributes[@"offset"];
        if ([WXConvert isValidatedArray:offset]) {
            _offset = CGPointMake([WXConvert CGFloat:offset[0]],
                                  [WXConvert CGFloat:offset[1]]);//[WXConvert sizeToWXPixelType:attributes[@"offset"] withInstance:self.weexInstance];
        }
        if (styles[@"zIndex"]) {
            _zIndex = [styles[@"zIndex"] integerValue];
        }
        _hideCallout = [[attributes map_safeObjectForKey:@"hideCallout"] boolValue];
        NSArray *position = [attributes map_safeObjectForKey:@"position"];
        if ([WXConvert isValidatedArray:position]) {
            _location = [attributes map_safeObjectForKey:@"position"];
        }
        _title = [attributes map_safeObjectForKey:@"title"];
        _icon = [attributes map_safeObjectForKey:@"icon"];
    }
    return self;
}

- (void)updateAttributes:(NSDictionary *)attributes
{
    DMapViewComponent *mapComponent = (DMapViewComponent *)self.supercomponent;
    if (attributes[@"title"]) {
        _title = attributes[@"title"];
        [mapComponent updateTitleMarker:self];
    }

    if ([attributes map_safeObjectForKey:@"icon"]) {
        _icon = attributes[@"icon"];
        [mapComponent updateIconMarker:self];
    }

    NSArray *position = [attributes map_safeObjectForKey:@"position"];
    if ([WXConvert isValidatedArray:position]) {
        _location = position;
        [mapComponent updateLocationMarker:self];

    }
}
  • 2.3 dwd-weex-amap-info-window YFjqQnE.jpg!web 思路:
1. 新建DMapInfoWindowComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addAnnotation方法添加DMapInfoWindowComponent组件  
3. 在DMapViewComponent重写insertSubview方法来添加子组建信息窗体

部分代码:

- (instancetype)initWithRef:(NSString *)ref
                       type:(NSString*)type
                     styles:(nullable NSDictionary *)styles
                 attributes:(nullable NSDictionary *)attributes
                     events:(nullable NSArray *)events
               weexInstance:(WXSDKInstance *)weexInstance
{
    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
    if (self) {
        if (attributes[@"open"]) {
            _isOpen = [attributes[@"open"] boolValue];
        }

    }
    return self;
}

- (UIView *) loadView
{
    return [[DMapInfoWindow alloc] initWithAnnotation:_annotation reuseIdentifier:_identifier];
}

- (void)insertSubview:(WXComponent *)subcomponent atIndex:(NSInteger)index{}
- (void)updateAttributes:(NSDictionary *)attributes
{
    [super updateAttributes:attributes];
    if (attributes[@"open"])
    {
        _isOpen = [attributes[@"open"] boolValue];
        if (_isOpen) {
            [self _addSubView];
        }else {
            [self _removeViewFromSuperView];
        }
    }
}

#pragma mark - private method
- (void)_addSubView
{
    [self _removeViewFromSuperView];
    [(DMapViewComponent *)self.supercomponent addMarker:self];
}

- (void)_removeViewFromSuperView
{
    [(DMapViewComponent *)self.supercomponent removeMarker:self];
}
  • 2.4 dwd-weex-amap-circle iqaI7jv.jpg!web 思路:
1. 新建DMapCircleComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addOverlay方法添加DMapCircleComponent组件  
3. 在DMapViewComponent重写insertSubview方法来添加子组建圆

部分代码:

- (instancetype)initWithRef:(NSString *)ref
                       type:(NSString*)type
                     styles:(nullable NSDictionary *)styles
                 attributes:(nullable NSDictionary *)attributes
                     events:(nullable NSArray *)events
               weexInstance:(WXSDKInstance *)weexInstance
{
    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
    if (self) {
        NSArray *centerArray = [attributes map_safeObjectForKey:@"center"];
        if ([WXConvert isValidatedArray:centerArray]) {
            _center = centerArray;
        }
        _radius = [[attributes map_safeObjectForKey:@"radius"] doubleValue];
    }
    return self;
}

- (void)updateAttributes:(NSDictionary *)attributes
{
    NSArray *centerArray = [attributes map_safeObjectForKey:@"center"];
    DMapViewComponent *parentComponent = (DMapViewComponent *)self.supercomponent;
    if ([WXConvert isValidatedArray:centerArray]) {
        _center = centerArray;
        [parentComponent removeOverlay:self];
        [parentComponent addOverlay:self];
    }else if ([[attributes map_safeObjectForKey:@"radius"] doubleValue] >= 0) {
        _radius = [[attributes map_safeObjectForKey:@"radius"] doubleValue];
        [parentComponent removeOverlay:self];
        [parentComponent addOverlay:self];
    }else {
        [super updateAttributes:attributes];
    }
}
  • 2.5 dwd-weex-amap-polygon vQB7ruQ.jpg!web 思路:
1. 新建DMapPolygonComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addOverlay方法添加DMapPolygonComponent组件  
3. 在DMapViewComponent重写insertSubview方法来添加子组建多边形

部分代码:

- (instancetype)initWithRef:(NSString *)ref
                       type:(NSString*)type
                     styles:(nullable NSDictionary *)styles
                 attributes:(nullable NSDictionary *)attributes
                     events:(nullable NSArray *)events
               weexInstance:(WXSDKInstance *)weexInstance
{
    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
    if (self) {
        _fillColor = [attributes map_safeObjectForKey:@"fillColor"];
        _fillOpacity = [attributes map_safeObjectForKey:@"fillOpacity"];
    }
    return self;
}

- (void)updateAttributes:(NSDictionary *)attributes
{
    if ([attributes map_safeObjectForKey:@"fillColor"]) {
        _fillColor = [attributes map_safeObjectForKey:@"fillColor"];
    }else if ([attributes map_safeObjectForKey:@"fillOpacity"]) {
        _fillOpacity = [attributes map_safeObjectForKey:@"fillOpacity"];
    }else {
        [super updateAttributes:attributes];
    }
}
  • 2.5 dwd-weex-amap-polyline 3y2Qviq.jpg!web 思路:
1. 新建DMapPolylineComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addOverlay方法添加DMapPolylineComponent组件  
3. 在DMapViewComponent重写insertSubview方法来添加子组建折线

部分代码:

@implementation DMapPolylineComponent


- (instancetype)initWithRef:(NSString *)ref
                       type:(NSString*)type
                     styles:(nullable NSDictionary *)styles
                 attributes:(nullable NSDictionary *)attributes
                     events:(nullable NSArray *)events
               weexInstance:(WXSDKInstance *)weexInstance
{
    self = [super initWithRef:ref type:type styles:styles attributes:attributes events:events weexInstance:weexInstance];
    if (self) {
        NSArray * pathArray = [attributes map_safeObjectForKey:@"path"];
        if ([WXConvert isValidatedArray:pathArray]) {
            _path = pathArray;
        }
        _strokeColor = [attributes map_safeObjectForKey:@"strokeColor"];
        _strokeWidth = [[attributes map_safeObjectForKey:@"strokeWidth"] doubleValue];
        _strokeOpacity = [[attributes map_safeObjectForKey:@"strokeOpacity"] doubleValue];
        _strokeStyle = [attributes map_safeObjectForKey:@"strokeStyle"];
    }
    _viewLoaded = NO;
    return self;
}

- (void)updateAttributes:(NSDictionary *)attributes
{
    NSArray * pathArray = [attributes map_safeObjectForKey:@"path"];
    DMapViewComponent *parentComponent = (DMapViewComponent *)self.supercomponent;
    if (pathArray) {
        if ([WXConvert isValidatedArray:pathArray]) {
            _path = pathArray;
        }
        [parentComponent removeOverlay:self];
        [parentComponent addOverlay:self];
        return;
    }else if ([attributes map_safeObjectForKey:@"strokeColor"]) {
        _strokeColor = [attributes map_safeObjectForKey:@"strokeColor"];
    }else if ([[attributes map_safeObjectForKey:@"strokeWidth"] doubleValue] >= 0) {
        _strokeWidth = [[attributes map_safeObjectForKey:@"strokeWidth"] doubleValue];
    }else if ([[attributes map_safeObjectForKey:@"strokeOpacity"] doubleValue] >= 0) {
        _strokeOpacity = [[attributes map_safeObjectForKey:@"strokeOpacity"] doubleValue];
    }else if ([attributes map_safeObjectForKey:@"strokeStyle"]) {
        _strokeStyle = [attributes map_safeObjectForKey:@"strokeStyle"];
    }
    [parentComponent updateOverlayAttributes:self];
}

@end

3.weex-android地图组件扩展方式介绍**

  • 3.1 dwd-weex-amap mQr6Z3u.jpg!web 思路:
1. 新建DMapViewComponent类继承WXVContainer实现LocationSource  
2.使用initComponentHostView(context)初始化  
3.在DMapViewComponent实现文件中实现初始化map对象initMap,设置map的key  
4.@WXComponentProp注解实现属性绑定  
5.通过fireEvent添加适当时机可以触发的事件  
6.设置mapview的setInfoWindowAdapter,addPolyline,addPolygon,addCircle,addMarker等方式来实现覆盖物,,线,圆等等

部分代码:

@Override
    protected FrameLayout initComponentHostView(@NonNull Context context) {
        mapContainer = new FrameLayout(context) {
            @Override
            public boolean onInterceptTouchEvent(MotionEvent ev) {
                // 解决与Scroller的滑动冲突
                if (ev.getAction() == MotionEvent.ACTION_UP) {
                    requestDisallowInterceptTouchEvent(false);
                } else {
                    requestDisallowInterceptTouchEvent(true);
                }
                return false;
            }
        };
        mapContainer.setBackgroundColor(fakeBackgroundColor);
        if (context instanceof Activity) {
            mActivity = (Activity) context;
        }

        return mapContainer;
    }

    @Override
    protected void setHostLayoutParams(FrameLayout host, int width, int height, int left, int right, int top, int bottom) {
        super.setHostLayoutParams(host, width, height, left, right, top, bottom);
        if (!isMapLoaded.get() && !isInited.get()) {
            isInited.set(true);
            mapContainer.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mMapView = new TextureMapView(getContext());
                    mapContainer.addView(mMapView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.MATCH_PARENT));
                    WXLogUtils.e(TAG, "Create MapView " + mMapView.toString());
                    initMap();
                }
            }, 0);
        }
    }

    private void initMap() {
        mMapView.onCreate(null);
        isMapLoaded.set(false);
        if (mAMap == null) {
            mAMap = mMapView.getMap();

            mAMap.setInfoWindowAdapter(new InfoWindowAdapter(this));
            mAMap.setOnMapLoadedListener(new AMap.OnMapLoadedListener() {
                @Override
                public void onMapLoaded() {
                    WXLogUtils.e(TAG, "Map loaded");
                    isMapLoaded.set(true);
                    mZoomLevel = mAMap.getCameraPosition().zoom;
                    mMapView.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            execPaddingTasks();
                        }
                    }, 16);
                }
            });

            // 绑定 Marker 被点击事件
            mAMap.setOnMarkerClickListener(new AMap.OnMarkerClickListener() {
                // marker 对象被点击时回调的接口
                // 返回 true 则表示接口已响应事件,否则返回false
                @Override
                public boolean onMarkerClick(Marker marker) {

                    if (marker != null) {
                        for (int i = 0; i < getChildCount(); i++) {
                            if (getChild(i) instanceof DMapMarkerComponent) {
                                DMapMarkerComponent child = (DMapMarkerComponent) getChild(i);
                                if (child.getMarker() != null && child.getMarker().getId() == marker.getId()) {
                                    child.onClick();
                                }
                            }
                        }
                    }
                    return false;
                }
            });
            mAMap.setOnCameraChangeListener(new AMap.OnCameraChangeListener() {

                private boolean mZoomChanged;

                @Override
                public void onCameraChange(CameraPosition cameraPosition) {
                    mZoomChanged = mZoomLevel != cameraPosition.zoom;
                    mZoomLevel = cameraPosition.zoom;
                }

                @Override
                public void onCameraChangeFinish(CameraPosition cameraPosition) {
                    if (mZoomChanged) {

                        float scale = mAMap.getScalePerPixel();
                        float scaleInWeex = scale / WXViewUtils.getWeexPxByReal(scale);

                        VisibleRegion visibleRegion = mAMap.getProjection().getVisibleRegion();
                        WXLogUtils.d(TAG, "Visible region: " + visibleRegion.toString());
                        Map<String, Object> region = new HashMap<>();
                        region.put("northeast", convertLatLng(visibleRegion.latLngBounds.northeast));
                        region.put("southwest", convertLatLng(visibleRegion.latLngBounds.southwest));

                        Map<String, Object> data = new HashMap<>();
                        data.put("targetCoordinate", cameraPosition.target.toString());
                        data.put("zoom", cameraPosition.zoom);
                        data.put("tilt", cameraPosition.tilt);
                        data.put("bearing", cameraPosition.bearing);
                        data.put("isAbroad", cameraPosition.isAbroad);
                        data.put("scalePerPixel", scaleInWeex);
                        data.put("visibleRegion", region);
                        getInstance().fireEvent(getRef(), WeexConstant.EVENT.ZOOM_CHANGE, data);
                    }
                }
            });

            mAMap.setOnMapTouchListener(new AMap.OnMapTouchListener() {
                boolean dragged = false;

                @Override
                public void onTouch(MotionEvent motionEvent) {

                    switch (motionEvent.getAction()) {
                        case MotionEvent.ACTION_MOVE:
                            dragged = true;
                            break;
                        case MotionEvent.ACTION_UP:
                            if (dragged)
                                getInstance().fireEvent(getRef(), WeexConstant.EVENT.DRAG_CHANGE);
                            dragged = false;
                            break;
                    }
                }
            });
            setUpMap();
        }
    }
}
  • 3.2 dwd-weex-amap-marker IFfYJjN.jpg!web 思路:
1. 新建DMapViewMarkerComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addMarker方法添加DMapViewMarkerComponent组件

部分代码:

private void initMarker(final String title, final String position, final String icon) {
        postMapOperationTask((WXMapViewComponent) getParent(), new DMapViewComponent.MapOperationTask() {
            @Override
            public void execute(TextureMapView mapView) {
                final MarkerOptions markerOptions = new MarkerOptions();
                //设置Marker可拖动
                markerOptions.draggable(true);
                // 将Marker设置为贴地显示,可以双指下拉地图查看效果
                markerOptions.setFlat(true);
//                markerOptions.icon(BitmapDescriptorFactory.fromView(new View(getContext())));
                Marker marker = mapView.getMap().addMarker(markerOptions);
                setMarkerTitle(marker, title);
                setMarkerPosition(marker, position);
                setMarkerIcon(marker, icon);
                setWidget(marker);
                String ref = (String) getDomObject().getAttrs().get("markerRef");
                ((WXMapViewComponent) getParent()).getCachedMarker().put(ref, DMapMarkerComponent.this);
            }
        });
    }
  • 3.3 dwd-weex-amap-info-window y2yYnia.jpg!web 思路:
1. 新建DMapViewMarkerComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addMarker方法添加DMapViewMarkerComponent组件

部分代码:

private static class InfoWindowAdapter implements AMap.InfoWindowAdapter {

        private DMapViewComponent mWXMapViewComponent;

        InfoWindowAdapter(DMapViewComponent wxMapViewComponent) {
            mWXMapViewComponent = wxMapViewComponent;
        }

        @Override
        public View getInfoWindow(Marker marker) {
            return render(marker);
        }

        @Override
        public View getInfoContents(Marker marker) {
            return null;
//            return render(marker);
        }

        private View render(Marker marker) {
            WXMapInfoWindowComponent wxMapInfoWindowComponent = mWXMapViewComponent.mInfoWindowHashMap.get(marker.getId());
            if (wxMapInfoWindowComponent != null) {
                WXFrameLayout host = wxMapInfoWindowComponent.getHostView();
//                WXFrameLayout content = (WXFrameLayout) host.getChildAt(0);
                host.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
                host.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT;
                WXLogUtils.d(TAG, "Info size: " + host.getMeasuredWidth() + ", " + host.getMeasuredHeight());
                return host;
            } else {
                WXLogUtils.e(TAG, "WXMapInfoWindowComponent with marker id " + marker.getId() + " not found");
            }
            return null;
        }
    }
  • 3.4 dwd-weex-amap-circle NvMnmmA.jpg!web 思路:
1. 新建DMapViewMarkerComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addCircle方法添加DMapViewMarkerComponent组件

部分代码:

private void initCircle() {
        postMapOperationTask((DMapViewComponent) getParent(), new DMapViewComponent.MapOperationTask() {
            @Override
            public void execute(TextureMapView mapView) {
                CircleOptions circleOptions = new CircleOptions();
                circleOptions.strokeColor(mColor);
                circleOptions.strokeWidth(mWeight);
                circleOptions.radius(mRadius);
                circleOptions.fillColor(mFillColor);
                setWidget(mapView.getMap().addCircle(circleOptions));
            }
        });
    }
  • 3.5 dwd-weex-amap-polygon fqeaiaE.jpg!web 思路:
1. 新建DMapPolygonComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addPolygon方法添加DMapPolygonComponent组件

部分代码:

private void initPolygon() {
        postMapOperationTask((DMapViewComponent) getParent(), new DMapViewComponent.MapOperationTask() {
            @Override
            public void execute(TextureMapView mapView) {
                PolygonOptions polygonOptions = new PolygonOptions();
                polygonOptions.addAll(mPosition);
                polygonOptions.strokeColor(mColor);
                polygonOptions.strokeWidth(mWidth);
                setWidget(mapView.getMap().addPolygon(polygonOptions));
            }
        });
    }
  • 3.6 dwd-weex-amap-polyline baQBBvU.jpg!web 思路:
1. 新建DMapPolyLineComponent类继承WXComponent  
2.在DMapViewComponent中使用mapview的addPolyline方法添加DMapPolyLineComponent组件

部分代码:

private void initPolygon() {
        postMapOperationTask((DMapViewComponent) getParent(), new DMapViewComponent.MapOperationTask() {
            @Override
            public void execute(TextureMapView mapView) {
                PolygonOptions polygonOptions = new PolygonOptions();
                polygonOptions.addAll(mPosition);
                polygonOptions.strokeColor(mColor);
                polygonOptions.strokeWidth(mWidth);
                setWidget(mapView.getMap().addPolygon(polygonOptions));
            }
        });
    }

4.weex-html5地图组件扩展方式介绍**

  • 4.1 dwd-weex-amap QFjYfiY.jpg!web 基础示例:
<template>  
    <div class="amap-page-container">
      <el-amap ref="map" vid="amapDemo" :amap-manager="amapManager" :center="center" :zoom="zoom" :plugin="plugin" :events="events" class="amap-demo">
      </el-amap>

      <div class="toolbar">
        <button @click="getMap()">get map</button>
      </div>
    </div>
  </template>

  <style>
    .amap-demo {
      height: 300px;
    }
  </style>

  <script>
    // NPM 方式
    // import { AMapManager } from 'vue-amap';
    // CDN 方式
    let amapManager = new VueAMap.AMapManager();
    module.exports = {
      data: function() {
        return {
          amapManager,
          zoom: 12,
          center: [121.59996, 31.197646],
          events: {
            init: (o) => {
              console.log(o.getCenter())
              console.log(this.$refs.map.$$getInstance())
              o.getCity(result => {
                console.log(result)
              })
            },
            'moveend': () => {
            },
            'zoomchange': () => {
            },
            'click': (e) => {
              alert('map clicked');
            }
          },
          plugin: ['ToolBar', {
            pName: 'MapType',
            defaultType: 0,
            events: {
              init(o) {
                console.log(o);
              }
            }
          }]
        };
      },

      methods: {
        getMap() {
          // amap vue component
          console.log(amapManager._componentMap);
          // gaode map instance
          console.log(amapManager._map);
        }
      }
    };
</script>
  • 4.2 dwd-weex-amap-marker UNjy2qb.jpg!web 基础示例:
<template>  
    <div class="amap-page-container">
      <el-amap vid="amapDemo" :zoom="zoom" :center="center" class="amap-demo">
        <el-amap-marker vid="component-marker" :position="componentMarker.position" :content-render="componentMarker.contentRender" ></el-amap-marker>
        <el-amap-marker v-for="(marker, index) in markers" :position="marker.position" :events="marker.events" :visible="marker.visible" :draggable="marker.draggable" :vid="index"></el-amap-marker>
      </el-amap>
      <div class="toolbar">
        <button type="button" name="button" v-on:click="toggleVisible">toggle first marker</button>
        <button type="button" name="button" v-on:click="changePosition">change position</button>
        <button type="button" name="button" v-on:click="chnageDraggle">change draggle</button>
        <button type="button" name="button" v-on:click="addMarker">add marker</button>
        <button type="button" name="button" v-on:click="removeMarker">remove marker</button>
      </div>
    </div>
  </template>

  <style>
    .amap-demo {
      height: 300px;
    }
  </style>

  <script>
    const exampleComponents = {
      props: ['text'],
      template: `<div>text from  parent: {{text}}</div>`
    }
    module.exports = {
      name: 'amap-page',
      data() {
        return {
          count: 1,
          slotStyle: {
            padding: '2px 8px',
            background: '#eee',
            color: '#333',
            border: '1px solid #aaa'
          },
          zoom: 14,
          center: [121.5273285, 31.21515044],
          markers: [
            {
              position: [121.5273285, 31.21515044],
              events: {
                click: () => {
                  alert('click marker');
                },
                dragend: (e) => {
                  console.log('---event---: dragend')
                  this.markers[0].position = [e.lnglat.lng, e.lnglat.lat];
                }
              },
              visible: true,
              draggable: false,
              template: '<span>1</span>',
            }
          ],
          renderMarker: {
            position: [121.5273285, 31.21715058],
            contentRender: (h, instance) => {
              // if use jsx you can write in this
              // return <div style={{background: '#80cbc4', whiteSpace: 'nowrap', border: 'solid #ddd 1px', color: '#f00'}} onClick={() => ...}>marker inner text</div>
              return h(
                'div',
                {
                  style: {background: '#80cbc4', whiteSpace: 'nowrap', border: 'solid #ddd 1px', color: '#f00'},
                  on: {
                    click: () => {
                      const position = this.renderMarker.position;
                      this.renderMarker.position = [position[0] + 0.002, position[1] - 0.002];
                    }
                  }
                },
                ['marker inner text']
              )
            }
          },
          componentMarker: {
            position: [121.5273285, 31.21315058],
            contentRender: (h, instance) => h(exampleComponents,{style: {backgroundColor: '#fff'}, props: {text: 'father is here'}}, ['xxxxxxx'])
          },
          slotMarker: {
            position: [121.5073285, 31.21715058]
          }
        };
      },
      methods: {
        onClick() {
          this.count += 1;
        },
        changePosition() {
          let position = this.markers[0].position;
          this.markers[0].position = [position[0] + 0.002, position[1] - 0.002];
        },
        chnageDraggle() {
          let draggable = this.markers[0].draggable;
          this.markers[0].draggable = !draggable;
        },
        toggleVisible() {
          let visableVar = this.markers[0].visible;
          this.markers[0].visible = !visableVar;
        },
        addMarker() {
          let marker = {
            position: [121.5273285 + (Math.random() - 0.5) * 0.02, 31.21515044 + (Math.random() - 0.5) * 0.02]
          };
          this.markers.push(marker);
        },
        removeMarker() {
          if (!this.markers.length) return;
          this.markers.splice(this.markers.length - 1, 1);
        }
      }
    };
</script>
  • 4.3 dwd-weex-amap-info-window ruqYFvm.jpg!web 基础示例:
<template>  
    <div class="amap-page-container">
      <el-amap vid="amap" :zoom="zoom" :center="center" class="amap-demo">
        <el-amap-info-window
          :position="currentWindow.position"
          :content="currentWindow.content"
          :visible="currentWindow.visible"
          :events="currentWindow.events">
        </el-amap-info-window>
      </el-amap>
      <button @click="switchWindow(0)">Show First Window</button>
      <button @click="switchWindow(1)">Show Second Window</button>
    </div>
  </template>

  <style>
    .amap-demo {
      height: 300px;
    }
  </style>

  <script>
    module.exports = {
      data () {
        return {
          zoom: 14,
          center: [121.5273285, 31.21515044],
          windows: [
            {
              position: [121.5273285, 31.21515044],
              content: 'Hi! I am here!',
              visible: true,
              events: {
                close() {
                  console.log('close infowindow1');
                }
              }
            }, {
              position: [121.5375285, 31.21515044],
              content: 'Hi! I am here too!',
              visible: true,
              events: {
                close() {
                  console.log('close infowindow2');
                }
              }
            }
          ],
          slotWindow: {
            position: [121.5163285, 31.21515044]
          },
          currentWindow: {
            position: [0, 0],
            content: '',
            events: {},
            visible: false
          }
        }
      },

      mounted() {
        this.currentWindow = this.windows[0];
      },

      methods: {
        switchWindow(tab) {
          this.currentWindow.visible = false;
          this.$nextTick(() => {
            this.currentWindow = this.windows[tab];
            this.currentWindow.visible = true;
          });
        }
      }
    };
</script>
  • 4.4 dwd-weex-amap-circle QN77fi3.jpg!web 基础示例:
<template>  
    <div class="amap-page-container">
      <el-amap vid="amapDemo" :zoom="zoom" :center="center" class="amap-demo">
        <el-amap-circle v-for="circle in circles" :center="circle.center" :radius="circle.radius" :fill-opacity="circle.fillOpacity" :events="circle.events"></el-amap-circle>
      </el-amap>
    </div>
  </template>

  <style>
    .amap-page-container {
      height: 200px;
    }
  </style>

  <script>
    module.exports = {
      data () {
        return {
          zoom: 15,
          center: [121.5273285, 31.21515044],
          circles: [
            {
              center: [121.5273285, 31.21515044],
              radius: 200,
              fillOpacity: 0.5,
              events: {
                click: () => {
                  alert('click');
                }
              }
            }
          ]
        }
      }
    };
</script>
  • 4.5 dwd-weex-amap-polygon iYnaArI.jpg!web 基础示例:
<template>  
     <div class="amap-page-container">
        <el-amap vid="amapDemo" :zoom="zoom" :center="center" class="amap-demo">
          <el-amap-rectangle v-for="retangle in retangles" :events="retangle.events" :center="retangle.center" :bounds="retangle.bounds" :fill-color="retangle.fillColor" :fill-opacity="retangle.fillOpacity"></el-amap-rectangle>
        </el-amap>
      </div>
  </template>

  <style>
    .amap-page-container {
      height: 200px;
    }
  </style>

  <script>
    module.exports = {
      data () {
        return {
          zoom: 12,
          center: [121.5273285, 31.21515044],
          retangles: [
            {
              center: [121.5273285, 31.21515044],
              bounds: [[121.5273285, 31.21515044], [121.7276285, 31.24545044]],
              fillOpacity: 0.7,
              fillColor: '#ffffff',
              events: {
                click: () => {
                  alert('click');
                }
              }
            }
          ]
        }
      }
    };
</script>
  • 4.6 dwd-weex-amap-polyline EbiYruq.jpg!web 基础示例:
<template>  
    <div class="amap-page-container">
      <el-amap vid="amap" :zoom="zoom" :center="center" class="amap-demo">
        <el-amap-polyline :editable="polyline.editable"  :path="polyline.path" :events="polyline.events"></el-amap-polyline>
      </el-amap>

      <div class="toolbar">
        <button type="button" name="button" v-on:click="changeEditable">change editable</button>
      </div>
    </div>
  </template>

  <style>
    .amap-demo {
      height: 300px;
    }
  </style>

  <script>
    module.exports = {
      data() {
        return {
          zoom: 12,
          center: [121.5273285, 31.25515044],
          polyline: {
            path: [[121.5389385, 31.21515044], [121.5389385, 31.29615044], [121.5273285, 31.21515044]],
            events: {
              click(e) {
                alert('click polyline');
              },
              end: (e) => {
                let newPath = e.target.getPath().map(point => [point.lng, point.lat]);
                console.log(newPath);
              }
            },
            editable: false
          }
        };
      },
      methods: {
        changeEditable() {
          this.polyline.editable = !this.polyline.editable;
        }
      }
    };
</script>

5.获取地图数据(例如骑行路径规划)**

  • 5.1 weex-iOS地图骑行路径规划 基础示例:
- (void)searchRidingRouteFromLat:(int)fromLat fromLng:(int)fromLng toLat:(int)toLat toLng:(int)toLng {

    AMapRidingRouteSearchRequest *request = [[AMapRidingRouteSearchRequest alloc] init];
    request.origin = [AMapGeoPoint locationWithLatitude:INT_2_FLOAT(fromLat) / 1000000
                                              longitude:INT_2_FLOAT(fromLng) / 1000000];
    request.destination = [AMapGeoPoint locationWithLatitude:INT_2_FLOAT(toLat) / 1000000
                                                   longitude:INT_2_FLOAT(toLng) / 1000000];
    //发起路径搜索
    [self.aMapSearch AMapRidingRouteSearch:request];
}

- (void)onRouteSearchDone:(AMapRouteSearchBaseRequest *)request response:(AMapRouteSearchResponse *)response {
    if(response.route == nil) {
        return;
    }
    //通过AMapNavigationSearchResponse对象处理搜索结果
    AMapRoute *route = response.route;
    if (route.paths.count > 0) {
        AMapPath *amapPath = route.paths[0];
        NSArray *coordArray = amapPath.steps;
        NSMutableArray *mArray = [NSMutableArray array];
        NSArray *start = @[[NSString stringWithFormat:@"%f", request.origin.longitude], [NSString stringWithFormat:@"%f", request.origin.latitude]];
        [mArray insertObject:start atIndex:0];
        for (AMapStep *step in coordArray) {
            NSString *polistring = step.polyline;
            NSArray *array = [polistring componentsSeparatedByString:@";"];
            for (NSString *str in array) {
                NSArray *loc =[str componentsSeparatedByString:@","];
                [mArray addObject:loc];
            }
        }
        NSArray *end = @[[NSString stringWithFormat:@"%f", request.destination.longitude], [NSString stringWithFormat:@"%f", request.destination.latitude]];
        [mArray insertObject:end atIndex:mArray.count];
        [[DMessageChannelManager shared] postMessage:@"mapLines" andData:@{@"result": @"success", @"data": @{@"mapLines":mArray}}];
    }
}

- (void)AMapSearchRequest:(id)request didFailWithError:(NSError *)error
{
    NSLog(@"Error: %@", error);
}



@end
  • 5.2 weex-android地图骑行路径规划 基础示例:
private RouteTask.OnRouteCalculateListener calculateListener = new RouteTask.OnRouteCalculateListener() {
        @Override
        public void onRouteCalculate(RideRouteResult result, int code) {
            HashMap<String, Object> res = new HashMap<>(2);
            if (code == 1000 && result != null) {
                Map<String, Object> data = new HashMap<>(1);
                data.put("mapLines", getLatLngList(result.getPaths().get(0), routeTask.getStartPoint(), routeTask.getEndPoint()));
                res.put("result", "success");
                res.put("data", data);
            } else {
                res.put("result", "fail");
            }
            String dataJson = new Gson().toJson(res);
            NotifyDataManager.getInstance().postMessage("mapLines", dataJson);
            WXLogUtils.d("RideRouteResult Json: " + dataJson);
        }
    };
         routeTask.addRouteCalculateListener(calculateListener);

    /**
     * 通过首尾经纬度计算走路规划路径中所有经纬度
     *
     * @param fromLat
     * @param fromLng
     * @param toLat
     * @param toLng
     */
    @JSMethod
    public void searchRidingRouteFromLat(float fromLat, float fromLng, float toLat, float toLng) {
        LocationEntity fromLe = new LocationEntity();
        fromLe.lat = fromLat / 1e6;
        fromLe.lng = fromLng / 1e6;
        LocationEntity toLe = new LocationEntity();
        toLe.lat = toLat / 1e6;
        toLe.lng = toLng / 1e6;
        if (routeTask == null) {
            routeTask = RouteTask.getInstance(mWXSDKInstance.getContext());
            routeTask.addRouteCalculateListener(calculateListener);
        }
        routeTask.search(fromLe, toLe);
    }
  • 5.3 weex-web地图骑行路径规划 基础示例:
//根据起终点坐标规划骑行路线
    let stream = weex.requireModule('stream')
    stream.fetch({
      timeout:20000,
      method: 'GET',
      url: 'https://restapi.amap.com/v4/direction/bicycling?key=87453539f02a65cd6585210fa2e64dc9&origin='+fromLng/1000000+','+fromLat/1000000+'&destination='+toLng/1000000+','+toLat/1000000,
  }, (response) => {
    if (response.status == 200) {
      let apiData = JSON.parse(response.data)

      if(apiData.data){
        var polyline= new Array(); 
        polyline[0] = apiData.data.origin.split(",");
        var polylineList = apiData.data.paths['0'].steps[0].polyline.split(";");

        for(var i=0;i<polylineList.length;i++) {
          var polylinePoint = polylineList[i].split(",");
          polyline.push(polylinePoint);
        }
        polyline.push(apiData.data.destination.split(",")); //字符分割 
        callback({"result":"success","data": {"mapLines":polyline}});

      }


    }
  }, () => {})

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK