annotations.
add the MapKit framework to your project
#import <MapKit/MapKit.h>
@interface WhereamiViewController : UIViewController
<CLLocationManagerDelegate,MKMapViewDelegate>
{
CLLocationManager *locationManager;
IBOutlet MKMapView *worldView;
IBOutlet UIActivityIndicatorView *activityIndicator;
IBOutlet UIActivityIndicatorView *activityIndicator;
IBOutlet UITextField *locationTitleField;
}
@end
When a UITextField is activated, a keyboard appears
on the screen. (We’ll see why this happens later in this chapter.) The keyboard’s appearance is determined by a set of
the UITextField’s properties called UITextInputTraits. One of these properties is the type of the keyboard’s
return key. For this application, we want the return key to read Done.
2.Being a MapView Delegate
In the last chapter, you
worked directly with Core Location to find the user’s location. Now this won’t be necessary because an instance of
MKMapView knows how to use Core Location to find the user’s location. All you have to do is set the
showsUserLocation property of an MKMapView to YES, and it will find and show the user’s location on the map.
After the interface loads, the WhereamiViewController is sent the message viewDidLoad. This is when you will
tell the MKMapView to update its location. (We’ll talk about viewDidLoad in detail in Chapter 7.) Implement this
method in WhereamiViewController.m.
- (void)viewDidLoad
{
[worldView setShowsUserLocation:YES];
}
Now that we have the MKMapView to determine the location, we don’t need the locationManager to do it. Remove
the line of code that tells the locationManager to start updating in WhereamiViewController.m. Leave the rest of
the setup code for the location manager in place.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
/////////[locationManager startUpdatingLocation]; //remove
}
return self;
}
Using the documentation
The documentation is divided into four parts: API Reference, System Guides, Tools Guides, and Sample Code. The
API Reference shows you every class, protocol, function, structure, method, and anything else you may use from
Cocoa Touch. The System Guides give you high-level overviews and discussion about concepts in Cocoa Touch.
The Tools Guide is the manual for Xcode and the rest of the developer tools suite.
From the Help menu, choose Documentation and API Reference. The organizer window will appear with the
Documentation item selected (Figure 5.8). In the lefthand panel, find the search box at the top. Click the magnifying
glass icon in the search box and choose Show Find Options to show the Find Options panel, which allows you to
tailor your search. In the search box, enter MKMapViewDelegate.
When you search for a term, the results from each part of the documentation are listed in the table on the left side of
the window. The top section titled Reference is the API Reference.
Search results from the API Reference are contained in nested categories. Each result has an icon that indicates
whether it is a class, a method, a protocol, or something else. Collectively, we call these items symbols, and their
mappings are shown in Figure 5.9.
3.当定位到目前的位置时,zoon in ,
- (void)mapView:(MKMapView *)mapView
didUpdateUserLocation:(MKUserLocation *)userLocation
{
// Here we are... but how do we actually zoom?
}
region property of MKMapView is type:MKCoordinateRegion
MKCoordinateRegion has
two members of types CLLocationCoordinate2D and MKCoordinateSpan. The CLLocationCoordinate2D is the
center of the map and the MKCoordinateSpan determines the level of zoom
MKCoordinateRegionMakeWithDistance, allows you to specify a region with a
CLLocationCoordinate2D and the north-south and east-west limits of the zoom in meters. For the limits, we’ll use
250 by 250 meters. For the coordinate, we need the user’s location
CLLocationCoordinate2D 决定了地图中心的位置, 而MKCoordinateSpan 则是也该中心为参考,向南北和东西方扩展多少米. 从而表达了一个区域的概念.
MKCoordinateSpan 越小,那就是Zoon in 我们当前的位置拉
MKCoordinateRegionMakeWithDistance, allows you to specify a region with a
CLLocationCoordinate2D and the north-south and east-west limits of the zoom in meters. For the limits, we’ll use
250 by 250 meters. For the coordinate, we need the user’s location.
- (void)mapView:(MKMapView *)mapView
didUpdateUserLocation:(MKUserLocation *)userLocation
{
CLLocationCoordinate2D loc = [userLocation coordinate];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 250, 250);
[worldView setRegion:region animated:YES];
}
MKAnnotation
MKAnnotation is not a delegate protocol. Instead, it declares a set of methods that are useful to any class that wants to
display instances of itself on a map view. Imagine an application that maps everything in a neighborhood, including
restaurants, factories, and train stations. These classes could be very different and hierarchically unrelated in the
application, but if they conform to MKAnnotation, they all can be added to an MKMapView.
When an object conforming to MKAnnotation is added to an MKMapView, an instance of MKAnnotationView (or one
of its subclasses) is created and added to the map view. The MKAnnotationView keeps a pointer to the
MKAnnotation-conforming object that it represents so it can ask it for data as needed
Create BNRMapPoint Class
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
@interface BNRMapPoint : NSObject <MKAnnotation>
{
}
// A new designated initializer for instances of BNRMapPoint
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t;
// This is a required property from MKAnnotation
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
// This is an optional property from MKAnnotation
@property (nonatomic, copy) NSString *title;
@end
Switch to BNRMapPoint.m. (The keyboard shortcut for switching between the header file and the implementation file
is Command-Control-Up arrow.) Synthesize the properties and add the implementation for the initializer.
#import "BNRMapPoint.h"
@implementation BNRMapPoint
@synthesize coordinate, title;
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t
{
self = [super init];
if (self) {
coordinate = c;
[self setTitle:t];
}
return self;
}
@end
In our code, we declared coordinate as a readonly property just like the protocol does. But we didn’t have to. We
could have just implemented a coordinate method that returns a CLLocationCoordinate2D. The MKAnnotation
protocol, like all protocols, only dictates method signatures. As long as the signatures match exactly, the conforming
class can implement them however it wants.
MKAnnotationView has an annotation
property declared as
@property (nonatomic, retain) id <MKAnnotation> annotation;
This declaration says that the annotation can be of any type (id), as long as it conforms to the MKAnnotation
protocol (<MKAnnotation>). Therefore, the MKAnnotationView will only send messages from the MKAnnotation
protocol to its annotation; it won’t make any assumptions about the other messages that object might respond to.
4.
Tagging locations
Now that you have a class that conforms to MKAnnotation, you can display instances of it on the map. The user will
enter the location’s name in the UITextField and then tap the Done button on the keyboard. The tapping of the
Done button is the signal to add an annotation. How will we know this event has occurred? Delegation, again
In the XIB file, you set the text field’s delegate to be the instance of WhereamiViewController. This means you
can send WhereamiViewController messages in the UITextFieldDelegate protocol. One of these methods is
textFieldShouldReturn:. When the keyboard’s return key is tapped, the UITextField sends this message to its
delegate and asks if it really should return. In this method, the delegate has the opportunity to perform tasks that
should coincide with the returning of the text field.
In WhereamiViewController.h, declare that WhereamiViewController conforms to the UITextFieldDelegate
protocol.
@interface WhereamiViewController : UIViewController
<CLLocationManagerDelegate, MKMapViewDelegate,
UITextFieldDelegate>
{
In WhereamiViewController.m, implement textFieldShouldReturn:.
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
// This method isn't implemented yet - but will be soon.
[self findLocation];
[textField resignFirstResponder];
return YES;
}
First, let’s talk about text
editing and the first responder. UIResponder is a class in the UIKit framework. A responder is responsible for
receiving and handling events that are associated with it. UIView is a subclass of UIResponder. Therefore, UIView
objects can receive events. A button is a responder that handles touch events, like a tap. Shaking a device and tapping
a key on the keyboard also generate events.
One of the responders is the first responder. Only one responder can be the first responder at a time. The first
responder handles events that aren’t associated with a position on the screen. For instance, a tap is sent to the view
object that was tapped, but shaking the device has no position on the screen, so that event is sent to the first responder
instead. We’ll talk more about the first responder and event-handling in Chapter 6 and Chapter 19.
For now, let’s focus on UITextField. A UITextField is also a responder: it is a direct subclass of UIControl,
which is a subclass of UIView, which is a subclass of UIResponder. When a UITextField is tapped, it handles this
event by becoming the first responder.
When a UITextField becomes the first responder, a keyboard automatically appears on the screen. To remove the
keyboard from the screen, you tell the UITextField to give up its first responder status by sending it the message
resignFirstResponder. Once the first responder is no longer a UITextField, the keyboard will disappear.
(Everything about UITextField holds true for the class UITextView, too. The difference between UITextView and
UITextField is that UITextView allows for multi-line editing: a text view’s return key enters the newline character
whereas a text field’s return key dispatches the delegate method textFieldShouldReturn:.)
- (void)findLocation
{
[locationManager startUpdatingLocation];
[activityIndicator startAnimating];
[locationTitleField setHidden:YES];
}
- (void)foundLocation:(CLLocation *)loc
{
CLLocationCoordinate2D coord = [loc coordinate];
// Create an instance of BNRMapPoint with the current data
BNRMapPoint *mp = [[BNRMapPoint alloc] initWithCoordinate:coord
title:[locationTitleField text]];
// Add it to the map view
[worldView addAnnotation:mp];
// Zoom the region to this location
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(coord, 250, 250);
[worldView setRegion:region animated:YES];
// Reset the UI
[locationTitleField setText:@""];
[activityIndicator stopAnimating];
[locationTitleField setHidden:NO];
[locationManager stopUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(@"%@", newLocation);
// How many seconds ago was this new location created?
NSTimeInterval t = [[newLocation timestamp] timeIntervalSinceNow];
// CLLocationManagers will return the last found location of the
// device first, you don't want that data in this case.
// If this location was made more than 3 minutes ago, ignore it.
if (t < -180) {
// This is cached data, you don't want it, keep looking
return;
}
[self foundLocation:newLocation];
}