在客户端绘制点、线、面要素是GIS应用的基本功能,这一讲我将向大家介绍在iOS中如何来实现这一功能。大家都知道在Flex、Silverlight、js中对于要素的绘制都有一个叫GraphicsLayer的图层,那么在ArcGIS for iOS中也不例外,具体的功能和用法也比较类似。同时,在ArcGIS for iOS中还有一个实用的图层叫AGSSketchGraphicsLayer(草图编辑图层),它不仅可以方便客户要素的绘制保存,也是实现离线在线编辑同步的利器。
另外,在Objective-C中委托是一种普遍采用的设计模式,而且ArcGIS for iOS中基本都是通过协议来实现的,比如要素绘制需要使用到AGSMapViewTouchDelegate协议来实现相应的委托。委托是将一个对象需要完成的处理委托给另外的对象来实现。委托有多种实现方式,协议只是其中一种,不能够将协议和委托混为一体。而协议是一组具有相似功能的函数集,它只定义了应该如何来完成相应的处理,具体的实现只能由其它类(也可以是自己)来完成。下面我就带大家来一步一步使用协议来实现委托处理完成要素绘制的功能。
首先,我们通过上一讲中的操作来构建具有GIS功能的工程,然后添加GraphicsLayer,并添加协议
@interface esriViewController : UIViewController<AGSMapViewTouchDelegate>
@property (retain, nonatomic) IBOutlet AGSMapView *mapView;
@property (retain, nonatomic) IBOutlet AGSGraphicsLayer *graphicsLayer;
@end
使用ArcGIS for iOS的协议实现委托处理的流程非常简单,只需要在类的声明中包含相应的协议
UIViewController<AGSMapViewTouchDelegate>,然后在实现协议的处理方法(协议中定义的必须实现的函数),如
-(void)mapView:(AGSMapView *)mapView didClickAtPoint:(CGPoint)screen mapPoint:(AGSPoint *)mappoint graphics:(NSDictionary *)graphics { //客户端要素绘制 //构建点要素的渲染样式 AGSPictureMarkerSymbol *pt=[AGSPictureMarkerSymbol pictureMarkerSymbolWithImageNamed:@"ArcGIS.bundle/GpsDisplay.png"]; //创建点要素 AGSGraphic *myPt=[[AGSGraphic alloc]initWithGeometry:mappoint symbol:pt attributes:nil infoTemplateDelegate:nil]; //添加要素到graphicsLayer [_graphicsLayer addGraphic:myPt]; [self.graphicsLayer dataChanged]; //将坐标信息以callout方式来显示出来 NSString *ltn= [NSString stringWithFormat:@"纬度:%0.4f 纬度:%0.4f",mappoint.x,mappoint.y]; self.mapView.callout.title=@"您当前点击的位置:"; self.mapView.callout.detail=ltn; self.mapView.callout.accessoryButtonHidden=YES; self.mapView.callout.image=[UIImage imageNamed:@"ArcGIS.bundle/esri.png"]; self.mapView.callout.autoAdjustWidth=YES; [self.mapView showCalloutAtPoint:(AGSPoint *)mappoint forGraphic:myPt animated:YES];
设置委托
_mapView.touchDelegate=self;(设置mapView的点击后的处理由该类esriViewController本身来实现)
效果
以上给大家介绍了使用ArcGIS for iOS协议实现委托的基本流程,以及GraphicsLayer实现要素绘制的功能,当然可以通过这种方式来添加多中用户自定义的要素信息。其实,ArcGIS for iOS的SDK已经给我们封装好了多种协议,如AGSMapViewTouchDelegate、AGSQueryTaskDelegate、AGSGeoprocessorDelegate等,在我们实现相应功能时,只需要引用即可,十分方便。
下面我们来看AGSSketchGraphicsLayer的使用,实现点、线、面的绘制。同样,首先,添加AGSSketchGraphicsLayer图层,并添加一个
UISegmentedControl组件,实现点、线、面、取消等操作。为了省去代码绑定的环节我采用上讲中右键画线到.h文件的形式来实现类的声明
#import <UIKit/UIKit.h> #import <ArcGIS/ArcGIS.h> @interface esriViewController : UIViewController<AGSMapViewTouchDelegate> @property (retain, nonatomic) IBOutlet AGSMapView *mapView; @property (retain, nonatomic) IBOutlet UISegmentedControl *selectGeometry; @property (retain, nonatomic) IBOutlet AGSGraphicsLayer *graphicsLayer; @property (retain, nonatomic) IBOutlet AGSSketchGraphicsLayer *sketchLayer; @end
viewDidLoad函数如下:
- (void)viewDidLoad { [super viewDidLoad]; //底图加载 NSURL *mapUrl = [NSURL URLWithString:@"http://www.arcgisonline.cn/ArcGIS/rest/services/ChinaOnlineStreetColor/MapServer"]; AGSTiledMapServiceLayer* baseMap=[[AGSTiledMapServiceLayer alloc] initWithURL:mapUrl]; [self.mapView addMapLayer:baseMap withName:@"TiledMapLayer"]; [baseMap release]; //要素图层的初始化与加载 self.graphicsLayer=[AGSGraphicsLayer graphicsLayer]; [self.mapView addMapLayer:self.graphicsLayer withName:@"GraphicsLayer"]; //草图的初始化与加载 _sketchLayer= [[[AGSSketchGraphicsLayer alloc] initWithGeometry:nil] autorelease]; [self.mapView addMapLayer:_sketchLayer withName:@"Sketch layer"]; //设置sketchLayer的默认geometry;不设置的情况,程序运行后直接在地图上点击不会得到点要素; _mapView.touchDelegate=_sketchLayer; _sketchLayer.geometry = [[[AGSMutablePoint alloc] initWithX:NAN y:NAN spatialReference:_mapView.spatialReference]autorelease]; //为UISegmentedControl绑定事件消息 [_selectGeometry addTarget:self action:@selector(selectAction:) forControlEvents: UIControlEventValueChanged]; }
在selectAction中设置要绘制要素的类型
-(void)selectAction:(id)sender { //设置地图点击后的处理由AGSSketchGraphicsLayer来实现; _mapView.touchDelegate=_sketchLayer; switch ([sender selectedSegmentIndex]) { case 0: { //点 _sketchLayer.geometry = [[[AGSMutablePoint alloc] initWithX:NAN y:NAN spatialReference:_mapView.spatialReference]autorelease]; } case 1: { //线 _sketchLayer.geometry = [[[AGSMutablePolyline alloc] initWithSpatialReference:_mapView.spatialReference] autorelease]; break; } case 2: { //面 _sketchLayer.geometry = [[[AGSMutablePolygon alloc] initWithSpatialReference:_mapView.spatialReference] autorelease]; break; } case 3: { //取消绘制操作; _mapView.touchDelegate=self; _sketchLayer.geometry=nil; break; } default: break; } }
AGSMapViewTouchDelegate实现函数
-(void)mapView:(AGSMapView *)mapView didClickAtPoint:(CGPoint)screen mapPoint:(AGSPoint *)mappoint graphics:(NSDictionary *)graphics { AGSGeometry* sketchGeometry = [[_sketchLayer.geometry copy] autorelease]; _mapView.touchDelegate=_sketchLayer; //将当前要素绘制到graphicsLayer; //看到alloc、copy、release、autorelease大家是否还记得之前讲Objective-C语法的内存管理呢,记得回忆下,你就有更加深刻的体会哦; AGSGraphic *gr=[[AGSGraphic alloc]initWithGeometry:sketchGeometry symbol:nil attributes:nil infoTemplateDelegate:nil]; [_graphicsLayer addGraphic:gr]; [_graphicsLayer dataChanged]; }
效果
总结:本讲主要希望通过要素绘制的功能,来向大家展示使用协议的方式实现委托模式的基本流程,AGSGraphicsLayer与AGSSketchGraphicsLayer的使用、callout信息显示等功能。下一讲我将通过QueryTask的实现来给大家介绍ArcGIS for iOS中Tasks使用的一般流程,欢迎大家继续关注!