Upload
tom-fan
View
453
Download
1
Embed Size (px)
DESCRIPTION
MapKit 和文本输入
Citation preview
MapKit 和⽂文本输⼊入
范圣刚,[email protected],www.tfan.org
•在这⼀一章,我们将使⽤用 MapKit 框架,UITextField 类以及更多的 delegation 来完成 Whereami 应⽤用。
•⺫⽬目前,whereami 找到位置并且在控制台打印出来。这章结束时,应⽤用程序将显⽰示出当前位置的地图.并且⽤用户还有⼀一个可选项,可以使⽤用MapKit annotation 标记和命名当前的位置。默认的 MapKit annotation 显⽰示为地图上的⼀一个红⾊色的⼤大头针。
完成后的 Whereami
对象⽰示意图(Object Diagrams)
view objects
•MKAnnotationView
•在 MKMapView 上作为图标显⽰示的⼏几个 MKAnnotationView 的实例
•MKMapView
•显⽰示地图,和所记录的位置的标签•UIActivityIndicatorView
•表⽰示当前设备还在⼯工作,没有⽌止步不前•UITextField
•允许⽤用户输⼊入⽂文本来给地图上的当前位置打标签
model objects
• CLLocationManager
•和设备交互以确定⽤用户位置• BNRMapPoint
•我们⾃自⼰己创建的模型对象
controller object
•WhereamiViewController
•负责处理来⾃自其他对象的更新和请求•是 MKMapView 的 delegate
• 当⼀一个 view 或者多个 views 被添加上以后 MKMapView 会发送 mapView:didAddAnnotationViews:
•是 UITextField 的 delegate
• ⽤用户完成输⼊入⽂文本后,UITextField 会发送 textFieldShouldReturn:
•是 CLLocationManager 的 delegate
• 发送 locationManager:didUpdateLocations: 通知WhereamiViewController 位置已经更新
MapKit 框架• Core Location framework 告诉我们我们在世界上的什么地⽅方
•MapKit framework 把世界显⽰示给我们
•MapKit 的主要⼯工作都是由 MKMapView 类完成的•显⽰示⼀一个地图•追踪触控•以及显⽰示注释(annotation)
把 MapKit framework 加⼊入项⺫⽬目
导⼊入 MapKit 头⽂文件
#import <UIKit/UIKit.h>// 导⼊入 Core Location framework 的头⽂文件#import <CoreLocation/CoreLocation.h>// 导⼊入MapKit framework 的头⽂文件#import <MapKit/MapKit.h>
声明必要的实例变量
@interface WhereamiViewController : UIViewController <CLLocationManagerDelegate>{ CLLocationManager *locationManager; IBOutlet MKMapView *worldView; IBOutlet UIActivityIndicatorView *activityIndicator; IBOutlet UITextField *locationTitleField;}@end
界⾯面属性(Interface Properties)1.从界⾯面右侧的 object library 中拖拽 MKMapView 到
UIView 上2.再拖拽 UITextField, UIActivityIndicatorView 到
MKMapView 上,适当调整位置和⼤大⼩小3.设置 ViewController 中实例变量到新增加的视图的链接(IBOutlet指⽰示的)
4.设置新增加的视图的 delegate 到 ViewController
XIB 布局
Finished connections
调整 UITextField 属性•设置 Placeholder
•设置 Return Key
设置 UIActivityIndicator 属性•不转的时候⾃自动隐藏•勾选上“Hides When
Stopped”
作为 MapView 的 Delegate
•我们希望 Whereami 启动时,找到当前的位置并在地图上显⽰示
•上⼀一个主题我们直接使⽤用 Core Location 查找⽤用户的位置
•MKMapView 实例本⾝身知道如何使⽤用 Core Location 查找⽤用户位置•设置 MKMapView 的 showUserLocation 属性为 YES,然后它就会查找⽤用户的位置并把它显⽰示在地图上
•界⾯面加载完以后,WhereamiViewController 会被发送 viewDidLoad 消息,我们在这⾥里⾯面告诉 MKMapView 来更新它的位置。
修改 WhereamiViewController.m- (void)viewDidLoad{ [super viewDidLoad];! // Do any additional setup after loading the view, typically from a nib. [worldView setShowsUserLocation:YES];}
- (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]; } return self;}
MKMapViewDelegate
• delegate 中是否有⼀一个⽤用户位置更新的事件?
•可以使⽤用⽂文档
⽂文档• API Reference
• System Guides
• Tools Guides
• Sample Code
mapView:didUpdateUserLocation
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{}
•通知⽤用户位置更新
当前位置居中显⽰示并适当缩放•已有数据:MKUserLocation
•需要调⽤用⽅方法:- (void)setRegion:(MKCoordinateRegion)region animated:(BOOL)animated
MKCoordinateRegiontypedef struct {! CLLocationCoordinate2D center;! MKCoordinateSpan span;} MKCoordinateRegion;
typedef struct {! CLLocationDegrees latitude;! CLLocationDegrees longitude;} CLLocationCoordinate2D;
typedef double CLLocationDegrees;
typedef struct { CLLocationDegrees latitudeDelta; CLLocationDegrees longitudeDelta;} MKCoordinateSpan;
MKUserLocation@interface MKUserLocation : NSObject <MKAnnotation> { @private MKUserLocationInternal *_internal;}
// Returns YES if the user's location is being updated.@property (readonly, nonatomic, getter=isUpdating) BOOL updating;
// Returns nil if the owning MKMapView's showsUserLocation is NO or the user's location has yet to be determined.@property (readonly, retain, nonatomic) CLLocation *location;
// Returns nil if not in MKUserTrackingModeFollowWithHeading@property (readonly, nonatomic, retain) CLHeading *heading NS_AVAILABLE(NA, 5_0);
// The title to be displayed for the user location annotation.@property (nonatomic, copy) NSString *title;
// The subtitle to be displayed for the user location annotation.@property (nonatomic, copy) NSString *subtitle;
@end
MKAnnotation@protocol MKAnnotation <NSObject>
// Center latitude and longitude of the annotion view.// The implementation of this property must be KVO compliant.@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@optional
// Title and subtitle for use by selection UI.@property (nonatomic, readonly, copy) NSString *title;@property (nonatomic, readonly, copy) NSString *subtitle;
// Called as a result of dragging an annotation view.- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate NS_AVAILABLE(NA, 4_0);
@end
MKAnnotation
•MKAnnotation 不是 delegate protocol
•声明了⼀一套对于任何想要把⾃自⼰己的实例显⽰示到 map view 上的类⾮非常有⽤用的⽅方法
•⽐比⽅方附近的酒店,⼯工⼚厂,⽕火⻋车站.... 这些类在应⽤用程序中都是⾮非常不同并且层次⽆无关的,但是只要他们满⾜足 MKAnnotation, 它们都可以被添加到 MKMapView
MKAnnotationView
•当⼀一个满⾜足 MKAnnotation 的对象被添加到 MKMapView 时,⼀一个MKAnnotationView 的实例会被创建并添加到 map view
•这个 MKAnnotationView 持有⼀一个到这个对象的指针,以便需要的时候可以向它请求数据
MKMapView 和 annotation
BNRMapPoint
•新建⼀一个类 BNRMapPoint, 让它遵守 MKAnnotation
•声明两个属性和⼀一个初始化器
BNRMapPoint.h
#import <Foundation/Foundation.h>#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>
@interface BNRMapPoint : NSObject <MKAnnotation>{ }
-(id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t;
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, copy) NSString *title;
@end
BNRMapPoint.m
@implementation BNRMapPoint
@synthesize coordinate, title;
- (id)init{ return [self initWithCoordinate:CLLocationCoordinate2DMake(39.91503, 116.4631) title:@"央视新台址"];}
- (id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t{ self = [super init]; if (self) { coordinate = c; [self setTitle:t]; } return self;}@end
给位置打标签•现在我们有了⼀一个符合 MKAnnotation 的类(BNRMapPoint),我们可以把它的实例显⽰示在地图上
•⽤用户可以在 UITextField 中输⼊入位置的名称,然后按下 keyboard 上的 Done 按钮
•轻按 Done 是增加⼀一个 annotation 的信号,怎么才能知道这个事件发⽣生了呢? 还是 Delegation
textFieldShouldReturn@interface WhereamiViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate, UITextFieldDelegate>
- (BOOL)textFieldShouldReturn:(UITextField *)textField{ [self findLocation]; [textField resignFirstResponder]; return YES;}
!rst responder
•UIResponder 是 UIKit framework 的⼀一个类,⼀一个 responder 负责接收和处理与其相关的事件
•UIView 是 UIResponder 的⼦子类,因此 UIView 对象可以接收事件
•按钮是可以处理触控事件的 responder,像 tap
•晃动设备及点击键盘上的⼀一个键也会产⽣生事件• responders 之⼀一就是 !rst responder, 同⼀一时间只能有⼀一个 responder 可以作为 !rst responder
• !rst responder 处理那些不和屏幕上某⼀一具体位置相关的事件。举例:tap 和 shaking的区别
resignFirstResponder
•UITextField 也是⼀一个 responder:它是 UIControl 的直接⼦子类,UIControl 是 UIView 的⼦子类,UIView 是 UIResponder 的⼦子类
•当UITextField 被点击的时候,它通过变成 !rst responder 来处理事件
•当 UITextField 变成 !rst responder, ⼀一个键盘就会⾃自动出现在屏幕上;要从屏幕上移除键盘,要通过给它发送 resignFirstResponder 消息来告诉 UITextField 放弃它的 !rst responder 状态,⼀一旦 !rst responder 不再是 UITextField,键盘就会消失
拼合使⽤用
<> 和 “”
•和 C++ ⼀一样,从框架中包含的⽂文件使⽤用<>尖括号,⾃自⼰己编写的头⽂文件使⽤用“”引号
• #import <MapKit/MapKit.h>,表⽰示仅在系统库下⾯面查找这个⽂文件
• #import "BNRMapPoint.h",表⽰示⾸首先在项⺫⽬目⽂文件下查找,找不到的话再在系统库下⾯面查找