mapview

Displaying Maps

include an  #import <MapKit/MapKit.h>

 Map Kit supports three basic coordinate systems for specifying map data points:

  • map coordinate is a latitude and longitude on the spherical representation of the Earth. Map coordinates are the primary way of specifying locations on the globe. You specify individual map coordinate values using theCLLocationCoordinate2D structure. You can specify areas using the MKCoordinateSpan andMKCoordinateRegion structures.  // 经纬度

  • map point is an x and y value on the Mercator map projection. Map points are used for many map-related calculations instead of map coordinates because they simplify the mathematics involved in the calculations. In your app, you use map points primarily when specifying the shape and position of custom map overlays. You specify individual map points using the MKMapPoint structure. You can specify areas using the MKMapSizeand MKMapRect structures.  // 地图maprect  将地球仪平铺成的map视图坐标

  • point is a graphical unit associated with the coordinate system of a UIView object. Map points and map coordinates must be mapped to points before drawing custom content in a view. You specify individual points using the CGPoint structure. You can specify areas using the CGSize and CGRect structures.  //view

Map coordinate system conversion routines

Convert from

Convert to

Conversion routines

Map coordinates

Points

convertCoordinate:toPointToView: (MKMapView)

convertRegion:toRectToView: (MKMapView)

Map coordinates

Map points

MKMapPointForCoordinate

Map points

Map coordinates

MKCoordinateForMapPoint

MKCoordinateRegionForMapRect

Map points

Points

pointForMapPoint: (MKOverlayView)

rectForMapRect: (MKOverlayView)

Points

Map coordinates

convertPoint:toCoordinateFromView:(MKMapView)

convertRect:toRegionFromView: (MKMapView)

Points

Map points

mapPointForPoint: (MKOverlayView)

mapRectForRect: (MKOverlayView)

Adding a Map View to Your User Interface

To add a map programmatically,  create an instance  of the  MKMapView  class,  initialize  it using the initWithFrame:  method, and then add it as a subview to your view hierarchy.

    you never handle touch events directly in a map view. The map view itself is an opaque container for a complex view hierarchy that handles the display of map-related data and all interactions with that data. Any subviews you add to the map view retain the position specified by their  frame  property and do not scroll with the map contents. If you want content to remain fixed relative to a specific map coordinate (and thus scroll with the map itself), you must use annotations or overlays as described in  “Annotating Maps.”

    The value you assign to the  region property (or set using the setRegion:animated:  method) is usually not the same value that is eventually stored by that property.Setting the span of a region nominally defines the rectangle you want to view but also implicitly sets the zoom level for the map view itself. The map view cannot display arbitrary zoom levels and must adjust any regions you specify to match the zoom levels it supports. It chooses the zoom level that allows your entire region to be visible while still filling as much of the screen as possible. It then adjust the region property accordingly. To find out the resulting region without actually changing the value in the region property, you can use the regionThatFits: method of the map view.

    Zooming and Panning the Map Content

    Zooming and panning allow you to change the visible portion of the map at any time:

    Displaying the User’s Current Location on the Map

    Map Kit includes built-in support for displaying the user’s current location on the map. To show this location, set the showsUserLocation property of your map view object to YES. Doing so causes the map view to use Core Location to find the user’s location and add an annotation of type MKUserLocation to the map.

    The addition of the MKUserLocation annotation object to the map is reported by the delegate in the same way that custom annotations are. If you want to associate a custom annotation view with the user’s location, you should return that view from your delegate object’s mapView:viewForAnnotation: method. If you want to use the default annotation view, you should return nil from that method instead.

    Responding to User Interactions with a Map

    The MKMapView class reports significant map-related events to its associated delegate object. The delegate object is an object that conforms to the MKMapViewDelegate protocol. You provide this object in situations where you want to respond to the following types of events:

    • Changes to the visible region of the map

    • The loading of map tiles from the network

    • Changes in the user’s location

    • Changes associated with annotations and overlays.

    Annotating Maps

    Annotations 标注一个点 
    overlays标注一个区域

    Annotations are used to display content that can be defined by a single coordinate point. By contrast, overlays are used to display content that is defined by any number of points and may constitute one or more contiguous or noncontiguous shapes. 

    In order to display an annotation on a map, your app must provide two distinct objects:

    • An object that conforms to the MKAnnotation protocol and manages the data for the annotation. (This object is the annotation object.)                        -----数据

    • A view (derived from the MKAnnotationView class) used to draw the visual representation of the annotation on the map surface. (This is the annotation view.)-------视图

    1. Define an appropriate annotation object using one of the following options:

      • Use the MKPointAnnotation class to implement a simple annotation. This type of annotation contains properties for specifying the title and subtitle strings to display in the annotation’s onscreen callout bubble.

      • Define a custom object that conforms to the MKAnnotation protocol, as described in “Defining a Custom Annotation Object.” This type of annotation can store any type of data you want.

    2. Define an annotation view to present the data on screen. How you define your annotation view depends on your needs and may be one of the following:

    3. Implement the mapView:viewForAnnotation: method in your map view delegate.

      Your implementation of this method should dequeue an existing annotation view if one exists or create a new one. If your app supports multiple types of annotations, you must include logic in this method to create a view of the appropriate type for the provided annotation object. For more information about implementing this method, see “Creating Annotation Views from Your Delegate Object.”

    4. Add your annotation object to the map view using thaddAnnotation: or addAnnotations: method.

    Defining a Custom Annotation Object

    Creating a simple annotation object

    @interface MyCustomAnnotation : NSObject <MKAnnotation> {
        CLLocationCoordinate2D coordinate;
    }
    @property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
    - (id)initWithLocation:(CLLocationCoordinate2D)coord;
     
    // Other methods and properties.
    @end
    @implementation MyCustomAnnotation
    @synthesize coordinate;
     
    - (id)initWithLocation:(CLLocationCoordinate2D)coord {
        self = [super init];
        if (self) {
            coordinate = coord;
        }
        return self;
    }
    @end

    Using the Standard Annotation Views

    MKAnnotationView* aView = [[[MKAnnotationView alloc] initWithAnnotation:annotation
                                      reuseIdentifier:@"MyCustomAnnotation"] autorelease];
    aView.image = [UIImage imageNamed:@"myimage.png"];
    aView.centerOffset = CGPointMake(10, -20);

    Defining a Custom Annotation View

    Declaring a custom annotation view

    #import <UIKit/UIKit.h>
    #import <MapKit/MapKit.h>
     
    @interface MyCustomAnnotationView : MKAnnotationView
    {
       // Custom data members
    }
    // Custom properties and methods.
    @end

    Initializing a custom annotation view

    - (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier
    {
        self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
        if (self)
        {
            // Set the frame size to the appropriate values.
            CGRect  myFrame = self.frame;
            myFrame.size.width = 40;
            myFrame.size.height = 40;
            self.frame = myFrame;
     
            // The opaque property is YES by default. Setting it to
            // NO allows map content to show through any unrendered
            // parts of your view.
            self.opaque = NO;
        }
        return self;
    }

    Creating Annotation Views from Your Delegate Object

     Creating annotation views

    - (MKAnnotationView *)mapView:(MKMapView *)mapView
                          viewForAnnotation:(id <MKAnnotation>)annotation
    {
        // If it's the user location, just return nil.
        if ([annotation isKindOfClass:[MKUserLocation class]])
            return nil;
     
        // Handle any custom annotations.
        if ([annotation isKindOfClass:[MyCustomAnnotation class]])
        {
            // Try to dequeue an existing pin view first.
            MKPinAnnotationView*    pinView = (MKPinAnnotationView*)[mapView
            dequeueReusableAnnotationViewWithIdentifier:@"CustomPinAnnotationView"];
     
            if (!pinView)
            {
                // If an existing pin view was not available, create one.
               pinView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation
                           reuseIdentifier:@"CustomPinAnnotation"]
                                 autorelease];
                pinView.pinColor = MKPinAnnotationColorRed;
                pinView.animatesDrop = YES;
                pinView.canShowCallout = YES;
     
                // Add a detail disclosure button to the callout.
                UIButton* rightButton = [UIButton buttonWithType:
                                   UIButtonTypeDetailDisclosure];
                [rightButton addTarget:self action:@selector(myShowDetailsMethod:)
                                   forControlEvents:UIControlEventTouchUpInside];
                pinView.rightCalloutAccessoryView = rightButton;
            }
            else
                pinView.annotation = annotation;
     
            return pinView;
        }
     
        return nil;
    }

    - (void)animateToWorld:(WorldCity *)worldCity

    {    

        MKCoordinateRegion current = mapView.region;

        MKCoordinateRegion zoomOut = { { (current.center.latitude + worldCity.coordinate.latitude)/2.0 , (current.center.longitude + worldCity.coordinate.longitude)/2.0 }, {90, 90} };

        [mapView setRegion:zoomOut animated:YES];

    }


    - (void)animateToPlace:(WorldCity *)worldCity

    {

        MKCoordinateRegion region;

        region.center = worldCity.coordinate;

        MKCoordinateSpan span = {0.4, 0.4};

        region.span = span;

        [mapView setRegion:region animated:YES];

    }


    - (void)worldCitiesListController:(WorldCitiesListController *)controller didChooseWorldCity:(WorldCity *)aPlace

    {

        [self.navigationController dismissModalViewControllerAnimated:YES];

        self.title = aPlace.name;

        MKCoordinateRegion current = mapView.region;

        if (current.span.latitudeDelta < 10)

        {

            [self performSelector:@selector(animateToWorld:) withObject:aPlace afterDelay:0.3];

            [self performSelector:@selector(animateToPlace:) withObject:aPlace afterDelay:1.7];        

        }

        else

        {

            [self performSelector:@selector(animateToPlace:) withObject:aPlace afterDelay:0.3];        

        }

    }


    Managing the Map’s Annotation Objects

    The only way to eliminate annotation overcrowding is to remove some of the annotation objects from the map view. This typically involves implementing the  mapView:regionWillChangeAnimated:  and mapView:regionDidChangeAnimated:  methods to detect changes in the map zoom level. During a zoom change, you can add or remove annotations as needed based on their proximity to one another. You might also consider other criteria (such as the user’s current location) to eliminate some annotations.

     you can use theMKMetersBetweenMapPoints method to get absolute distances between two points. You can also use each coordinate as the center of a map rectangle and use the MKMapRectIntersectsRect function to find any intersections. For a complete list of functions, see Map Kit Functions Reference.

    Marking Your Annotation View as Draggable

    • In your annotation objects, implement the setCoordinate: method to allow the map view to update the annotation’s coordinate point.

    • When creating your annotation view, set its draggable property to YES.

    the map view calls the   mapView:annotationView:didChangeDragState:fromOldState:  method of its delegate to notify it of changes to the drag state of your view. You can use this method to affect or respond to the drag operation

    If you want to animate your view during a drag operation,you can do that by implementing a custom dragStatemethod in your annotation view. As the map view processes drag-related touch events, it updates the dragStateproperty of the affected annotation view. Implementing a custom dragState method gives you a chance to intercept these changes and perform additional actions, such as animate the appearance of your view. For example, the MKPinAnnotationView class raises the pin off the map when a drag operation starts and drops the pin back down on the map when it ends.

    Displaying Overlays on a Map

    You can use these coordinates to create contiguous or noncontiguous sets of lines, rectangles, circles, and other shapes, which can then be filled or stroked with color.

    In order to display an overlay on a map, your app must provide two distinct objects:

    • An object that conforms to the MKOverlay protocol and manages the data points for the overlay. (This object is the overlay object.)

    • A view (derived from the MKOverlayView class) used to draw the visual representation of the overlay on the map surface. (This is the overlay view.)

    Checklist for Adding an Overlay to the Map

    1. Define an appropriate overlay data object using one of the following options:

    2. Define an overlay view to present on the screen using one of the following options:

      • For standard shapes, use the MKCircleViewMKPolygonView, or MKPolylineView to represent the annotation. You can customize many of the drawing attributes of the final shape using these classes.

      • For custom shapes descended from MKShape, define an appropriate subclass of MKOverlayPathView to render the shape.

      • For all other custom shapes and overlays, subclass MKOverlayView and implement your custom drawing code.

    3. Implement the mapView:viewForOverlay: method in your map view delegate.

    4. Add your overlay data object to the map view using the addOverlay: method or one of many others.

    you can rearrange their Z-ordering of overlays in a map to ensure that specific overlays are always displayed on top of others.

    Using the Standard Overlay Objects and Views

     Creating a polygon overlay object

        // Define an overlay that covers Colorado.
        CLLocationCoordinate2D  points[4];
     
        points[0] = CLLocationCoordinate2DMake(41.000512, -109.050116);
        points[1] = CLLocationCoordinate2DMake(41.002371, -102.052066);
        points[2] = CLLocationCoordinate2DMake(36.993076, -102.041981);
        points[3] = CLLocationCoordinate2DMake(36.99892, -109.045267);
     
        MKPolygon* poly = [MKPolygon polygonWithCoordinates:points count:4];
        poly.title = @"Colorado";
     
        [map addOverlay:poly];

    Creating a polygon view for rendering a shape

    - (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
    {
        if ([overlay isKindOfClass:[MKPolygon class]])
        {
            MKPolygonView*    aView = [[[MKPolygonView alloc] initWithPolygon:(MKPolygon*)overlay] autorelease];
     
            aView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
            aView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
            aView.lineWidth = 3;
     
            return aView;
        }
     
        return nil;
    }

    Defining a Custom Overlay Object

    You can subclass  MKShape  or MKMultiPoint  to define new types of shape-based overlays or you can adopt the  MKOverlay  protocol into one of your app’s existing classes. 

    Whether you subclass or adopt the MKOverlay protocol, the work you have to do in any custom overlay object is the same. The main job of an overlay object is to vend two key pieces of information:

    • A coordinate defining the center point of the overlay

    • A bounding rectangle that completely encompasses the overlay’s content

    Defining a Custom Overlay View

    To create a custom overlay view, you must subclass MKOverlayView. (If you simply want to modify the drawing behavior of an existing shape-based overlay, you can subclass MKOverlayPathView instead.) In your custom implementation, you should implement the following methods:

    You can do this by marking your view as dirty using either the  setNeedsDisplayInMapRect:  or setNeedsDisplayInMapRect:zoomScale:  method.

    Unlike drawing in a normal view, drawing in an overlay view involves some special considerations, including the following:

    • Your drawing code should never use the view’s bounds or frame as reference points for drawing. Instead, it should use the map points associated with the overlay object to define shapes. Immediately before drawing, it should then convert those map points to points (CGPoint and so on) using the conversion routines found in the MKOverlayView class.

      Also, you typically do not apply the zoom scale value passed to this method directly to your content. Instead, you provide it only when a Map Kit function or method specifically requires it. As long as you specify content using map points and convert to points, your content should be scaled to the correct size automatically.

    • If you use UIKit classes and functions to draw, you must explicitly set up and clean up the drawing environment. Before issuing any calls, call thUIGraphicsPushContext function to make the context passed to your method the current context. When you are done drawing, call UIGraphicsPopContext to remove that context.

    • Remember that the map view may tile large overlays and render each tile on a separate thread. Your drawing code should therefore not attempt to modify variables or other data unless it can do so in a thread-safe manner.

     Drawing a gradient in a custom overlay view

    - (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContext:(CGContextRef)context
    {
       // Get the overlay bounding rectangle.
       MKMapRect  theMapRect = [self.overlay boundingMapRect];
       CGRect theRect = [self rectForMapRect:theMapRect];
     
       // Clip the context to the bounding rectangle.
       CGContextAddRect(context, theRect);
       CGContextClip(context);
     
       // Set up the gradient color and location information.
       CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB();
       CGFloat locations[4] = {0.0, 0.33, 0.66, 1.0};
       CGFloat components[16] = {0.0, 0.0, 1.0, 0.5,
                                 1.0, 1.0, 1.0, 0.8,
                                 1.0, 1.0, 1.0, 0.8,
                                 0.0, 0.0, 1.0, 0.5};
     
       // Create the gradient.
       CGGradientRef myGradient = CGGradientCreateWithColorComponents(myColorSpace, components, locations, 4);
       CGPoint start, end;
       start = CGPointMake(CGRectGetMidX(theRect), CGRectGetMinY(theRect));
       end = CGPointMake(CGRectGetMidX(theRect), CGRectGetMaxY(theRect));
     
       // Draw.
       CGContextDrawLinearGradient(context, myGradient, start, end, 0);
     
       // Clean up.
       CGColorSpaceRelease(myColorSpace);
       CGGradientRelease(myGradient);
    }

    Managing the Map’s Overlay Objects

     In cases where the bounding rectangles of two overlays do overlap, you can either remove one of the overlays or arrange their Z-order to control which one appears on top.
    one place to do so is in themapView:didAddOverlayViews: method of your map view delegate. When this method is called, you can use the MKMapRectIntersectsRect function to see if the added overlay intersects the bounds of any other overlays. 

    Using Overlays as Annotations

    The  MKOverlay  protocol conforms to the  MKAnnotation  protocol. As a result, all overlay objects are also annotation objectsand can be treated as one or both in your code. If you opt to treat an overlay object as both, you are responsible for managing that object in two places.If you want to display both an overlay view and annotation view for it, you must implement both the  mapView:viewForOverlay: andmapView:viewForAnnotation:  methods in your app delegate. It also means that you must add and remove the object from bot h the overlays and annotations arrays of your map.


    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值