开发者社区> ghost丶桃子> 正文

Introduction to MapKit Framework for iPhone Development

简介:
+关注继续查看

Maps are important part of our life. We use them daily to find places and directions. The MapKit framework makes it easy for developers to implement applications which can make use of the maps in the applications. In this article we are going to introduce the MapKit framework for iOS programming.






Concepts: 

There are several concepts that we must learn first before diving into the code. 

MKMapView: MKMapView is a UI control which is used to display map in iOS devices. 

Annotation: Annotations is information related to a particular place on the map. These include grocery stores, gas stations, malls or even custom information inserted by the user. 

AnnotationView: The visual appearance of Annotations are defined using the MKAnnotationView class. By default the annotations are displayed using the pin annotation view. 

Referencing the Frameworks: 

For this application we will be using the MapKit.framework and CoreLocation.framework. Add both the frameworks to your project using the Build Phases tab as shown below:



Displaying Map Using MKMapView Control: 

After adding the reference to the MapKit.framework and CoreLocation.framework libraries we are ready to create our MapKit application. The first step in using the MapKit framework is to display the map on the iOS device. This can easily be performed by using the MKMapView control. Let's drag and drop the MapView control on the user interface with the help of the interface builder. 

Also, make sure to link the MKMapView control to the controller. The MapKitDemoAppDelegate.h implementation is shown below: 

01

#import <UIKit/UIKit.h>

02

#import <MapKit/MapKit.h>

03

#import <CoreLocation/CoreLocation.h>

04

#import "MapPoint.h"

05

#import "LameAnnotationView.h"

06

 

07

@interface MapKitDemoAppDelegate : NSObject <UIApplicationDelegate,CLLocationManagerDelegate,MKMapViewDelegate,UITextFieldDelegate> {

08

 

09

    CLLocationManager *locationManager;

10

    IBOutlet MKMapView *mapView;

11

     

12

}

13

 

14

@property (nonatomic, retain) IBOutlet UIWindow *window;

15

@property (nonatomic,retain) IBOutlet MKMapView *mapView;

16

 

17

@end



Run the application and you will see the map of the world as shown in the following screenshot: 



Pretty cool right! 

We can even focus on the current position of the user using the following code: 

01

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

02

{

03

    self.mapView.delegate = self;     

04

         

05

    locationManager = [[CLLocationManager alloc] init];

06

    [locationManager setDelegate:self];

07

     

08

    [locationManager setDistanceFilter:kCLDistanceFilterNone];

09

    [locationManager setDesiredAccuracy:kCLLocationAccuracyBest];

10

     

11

    [self.mapView setShowsUserLocation:YES];

12

 

13

     

14

    // Override point for customization after application launch.

15

    [self.window makeKeyAndVisible];

16

    return YES;

17

}



The CLLocationManager class is responsible for fetching information about the user's location. The following line enables the mapView to show the user's current location. 

1

[self.mapView setShowsUserLocation:YES];



The following screenshot shows the effect: 



Although the user's location is focused in the map but currently is shows an eagle view of the location. We need to zoom into the location to get more details. This can be easily accomplished by using the following implementation: 

1

- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views

2

{    

3

    MKAnnotationView *annotationView = [views objectAtIndex:0];

4

    id<MKAnnotation> mp = [annotationView annotation];

5

    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate] ,250,250);

6

     

7

    [mv setRegion:region animated:YES];

8

}



didAddAnnotationViews is one of the delegate methods of the MKMapViewDelegate which will send the events to the current controller as setup inside the didFinishLaunchingWithOptions method: 

1

self.mapView.delegate = self;   



Since, there is currently only one annotation view added to the map we can access it using the [views objectAtIndex:0] method. MKCoordinateRegion creates a customized region on the map which can be zoomed in or out. The following screenshot shows the map zoomed in on the user's location. 



One thing to notice is that the simulator shows the user's current location  in California where the Apple's headquarter is located. In order to get the correct user location you must run the application on the device. In the next section we are going to add annotations to our map. 

Adding Annotations to the Map: 

We are going to create our own custom annotation by inheriting from the MKAnnotation class as shown in the implementation below: 

01

#import <Foundation/Foundation.h>

02

#import <CoreLocation/CoreLocation.h>

03

#import <MapKit/MapKit.h>

04

 

05

@interface MapPoint : NSObject<MKAnnotation> {

06

     

07

    NSString *title;

08

    NSString *subTitle;

09

    CLLocationCoordinate2D coordinate;

10

     

11

}

12

 

13

@property (nonatomic,readonly) CLLocationCoordinate2D coordinate;

14

@property (nonatomic,copy) NSString *title;

15

@property (nonatomic,copy) NSString *subTitle;

16

 

17

-(id) initWithCoordinate:(CLLocationCoordinate2D) c title:(NSString *) t subTitle:(NSString *) st;

18

 

19

@end



The didUpdateUserLocation method of the MKMapViewDelegate is called when a new location update is received by the map view. Inside this method we are going to create custom annotations and add them to the map. 

01

- (void)mapView:(MKMapView *)mv didUpdateUserLocation:(MKUserLocation *)userLocation

02

{

03

    CLLocationCoordinate2D userCoordinate = userLocation.location.coordinate;

04

     

05

    for(int i = 1; i<=5;i++)

06

    {

07

        CGFloat latDelta = rand()*.035/RAND_MAX -.02;

08

        CGFloat longDelta = rand()*.03/RAND_MAX -.015;

09

         

10

        CLLocationCoordinate2D newCoord = { userCoordinate.latitude + latDelta, userCoordinate.longitude + longDelta };

11

        MapPoint *mp = [[MapPoint alloc] initWithCoordinate:newCoord title:[NSString stringWithFormat:@"Azam Home %d",i] subTitle:@"Home Sweet Home"];    

12

        [mv addAnnotation:mp];

13

        [mp release];

14

         

15

    }

16

}



As shown in the above code we are creating annotations at random coordinates and then adding them to the map view control. The screenshot below shows the effect in action: 




If you click on any of the annotations it will pop out a callout with custom text. We can make the callout more attractive by adding a small house on the left or right hand side of the callout. In the next section we are going to demonstrate how to create custom annotations to our map. 

Implementing a Custom Annotation View: 

Before implementing a custom annotation view we can make use of the built-in annotation views for our map. MKPinAnnotationView also allows the user to attach different controls to the annotations. The leftCalloutAccessoryView and rightCalloutAccessoryView can be used to show custom items in the annotation. The following implementation shows how a custom image can be shown in the annotation callout: 

01

- (MKAnnotationView *)mapView:(MKMapView *)mv viewForAnnotation:(id <MKAnnotation>)annotation

02

{

03

    if([annotation isKindOfClass:[MKUserLocation class]])

04

    return nil;

05

     

06

    NSString *annotationIdentifier = @"PinViewAnnotation";

07

     

08

    MKPinAnnotationView *pinView = (MKPinAnnotationView *) [mapView

09

                                                            dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];

10

 

11

     

12

    if (!pinView)

13

    {

14

        pinView = [[[MKPinAnnotationView alloc]

15

                    initWithAnnotation:annotation

16

                    reuseIdentifier:annotationIdentifier] autorelease];

17

         

18

        [pinView setPinColor:MKPinAnnotationColorGreen];

19

        pinView.animatesDrop = YES;

20

        pinView.canShowCallout = YES;

21

         

22

        UIImageView *houseIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"house.png"]];

23

        pinView.leftCalloutAccessoryView = houseIconView;

24

        [houseIconView release];        

25

    }

26

    else

27

    {

28

        pinView.annotation = annotation;

29

    }

30

 

31

    return pinView;

32

 

33

}



In order to improve the performance of the map view control we are storing the annotations type using an identifier. This means if the same annotation is used in different parts of the map then we reuse the same annotation without creating it from scratch. Run the code and click on any of the green pin and you will see a similar output: 



Now, the annotations are displayed with an image but as you can see the image size is too big for the callout. We can easily adjust that using the following code: 

1

UIImageView *houseIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"house.png"]];

2

        [houseIconView setFrame:CGRectMake(0, 0, 30, 30)];

3

        pinView.leftCalloutAccessoryView = houseIconView;

4

        [houseIconView release];        



Now, run the application again and notice how the house fits perfectly inside the callout. 



Although we have customized the callout of the annotation we have not changed the appearance of the pin. The pin can easily be changed by creating a custom annotation view class and overriding the drawRect method. The implementation below creates a custom annotation view class called "LameAnnotationView" which inherits from MKAnnotationView. 

01

#import "LameAnnotationView.h"

02

 

03

@implementation LameAnnotationView

04

 

05

- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier

06

{

07

    self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];

08

    if (self != nil)

09

    {

10

        CGRect frame = self.frame;

11

        frame.size = CGSizeMake(60.0, 85.0);

12

        self.frame = frame;

13

        self.backgroundColor = [UIColor clearColor];

14

        self.centerOffset = CGPointMake(-5, -5);

15

    }

16

    return self;

17

}

18

 

19

-(void) drawRect:(CGRect)rect

20

{

21

    [[UIImage imageNamed:@"house.png"] drawInRect:CGRectMake(30, 30.0, 30.0, 30.0)];

22

}

23

 

24

@end



In order to use the our new LameAnnotationView we simply substitute the MKPinAnnotationView with LameAnnotationView as shown below: 

01

- (MKAnnotationView *)mapView:(MKMapView *)mv viewForAnnotation:(id <MKAnnotation>)annotation

02

{

03

    if([annotation isKindOfClass:[MKUserLocation class]])

04

    return nil;

05

     

06

    NSString *annotationIdentifier = @"PinViewAnnotation";

07

     

08

    LameAnnotationView *pinView = (LameAnnotationView *) [mapView

09

                                                            dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];

10

 

11

     

12

    if (!pinView)

13

    {

14

        pinView = [[[LameAnnotationView alloc]

15

                    initWithAnnotation:annotation

16

                    reuseIdentifier:annotationIdentifier] autorelease];

17

         

18

//[pinView setPinColor:MKPinAnnotationColorGreen];

19

       // pinView.animatesDrop = YES;

20

        pinView.canShowCallout = YES;

21

         

22

        UIImageView *houseIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"house.png"]];

23

        [houseIconView setFrame:CGRectMake(0, 0, 30, 30)];

24

        pinView.leftCalloutAccessoryView = houseIconView;

25

        [houseIconView release];        

26

    }

27

    else

28

    {

29

        pinView.annotation = annotation;

30

    }

31

 

32

    return pinView;

33

 

34

}



Run the application and you will notice that the default pin annotations views are now replaced with our custom LameAnnotationView. 



In the process of customizing our annotation views we have lost the animation effects. But this can easily be added again by using core animation library. The following code shows how to add drop animations to our custom annotation views. 

01

- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views

02

{

03

     

04

    // add the animation here

05

     

06

    CGRect visibleRect = [mapView annotationVisibleRect];

07

     

08

    for(MKAnnotationView *view in views)

09

    {

10

        if([view isKindOfClass:[LameAnnotationView class]])

11

        {

12

            CGRect endFrame = view.frame;

13

             

14

            CGRect startFrame = endFrame;

15

         

16

            startFrame.origin.y = visibleRect.origin.y - startFrame.size.height;

17

            view.frame = startFrame;

18

           

19

             

20

            [UIView beginAnimations:@"drop" context:NULL];

21

            [UIView setAnimationDuration:2];

22

             

23

             

24

            view.frame = endFrame;

25

            [UIView commitAnimations];

26

        }

27

    }

28

      

29

     

30

    MKAnnotationView *annotationView = [views objectAtIndex:0];

31

    id<MKAnnotation> mp = [annotationView annotation];

32

    MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance([mp coordinate] ,5000,5000);

33

     

34

    [mv setRegion:region animated:YES];

35

}



Now run the application and you will notice that the houses animates using the drop animation that we implemented in the didAddAnnotationViews method. 

Conclusion: 

In this article we learned how to get started with the MapKit framework. We also demonstrated how to write custom annotations and custom annotation views which can greatly enhance the user experience. 
  

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 330987132 | Go:217696290 | Python:336880185 | 做人要厚道,转载请注明出处!

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
18582 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
27727 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
21935 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
15292 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
19980 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
14855 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23523 0
1955
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载