在客戶端繪制點、線、面要素是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文件的形式來實現類的聲明
完成后esriViewController.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使用的一般流程,歡迎大家繼續關注!