定位处理与地图
一、定位处理
定位管理主要是通过GPS、蜂窝基站三角网、WiFi三种方式实现。
ios8系统下使用定位服务必须在info.plist中添加两条变量:
分别用于描述程序始终使用和使用期间使用定位的说明。对应手机设置中定位服务中的始终和使用应用程序期间两个选项。
1、在项目中引入框架CoreLoaction.framework。
2、创建一个定位服务管理类CLLocationManager来创建一个位置管理器,提供位置信息和高度信息,也可以监控进入和离开某个区域,还可以获得设备的运行方向。遵循代理
CLLocationManagerDelegate。
//定义坐标坐标 var currLocation : CLLocation!
//创建位置管理器,用于定位服务管理类,它能够给我们提供位置信息和高度信息,也可以监控设备进入或离开某个区域,还可以获得设备的运行方向 let locationManager : CLLocationManager = CLLocationManager()
//指定代理 locationManager.delegate = self //精确到1000米,距离过滤器,定义了设备移动后获得位置信息的最小距离 locationManager.distanceFilter = kCLLocationAccuracyBest //通过数字设置距离 // locationManager.distanceFilter = 200 //发出授权申请 //NSLocationAlwaysUsageDescription 和 NSLocationWhenInUseUsageDescription 。至于在plist添加的方法,就是在plist中添加一个键值对,然后把请求允许对应的Key值复制粘贴进去就可以了。value值是什么都可以,这个值会在请求允许的对话框中显示出来给用户看。总之是你自己定的。 locationManager.requestAlwaysAuthorization() //更新位置 locationManager.startUpdatingLocation() //更新方向 locationManager.startUpdatingHeading() print("定位开始")
通过didChangeAuthorizationStatus代理方法,可以获得设备是否允许使用定位服务。
//代理方法--判断是否可以使用定位服务 func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) { if status == CLAuthorizationStatus.NotDetermined || status == CLAuthorizationStatus.Denied { //允许使用定位服务 //开始启动定位服务更新 locationManager.startUpdatingLocation() //更新方向 locationManager.startUpdatingHeading() print("定位开始") } }
定位改变时委托会执行这个方法,通过定义一个CLLocation坐标对象来接收坐标值。
//距离改变就会收到该委托方法,获取地理位置信息 func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { //获取最新坐标 currLocation = locations.last //获取经度 longitudeTxt.text = "\(currLocation.coordinate.longitude)" //获取纬度 latitudeTxt.text = "\(currLocation.coordinate.latitude)" //获取高度 HeightTxt.text = "\(currLocation.altitude)" }
两个坐标之间的距离可以通过func distanceFromLocation(other:Double) ->Double方法得到:
//计算两点之间距离 let currentLocation = CLLocation(latitude: 53.204526, longitude: 50.111751) let targetLocation = CLLocation(latitude: 53.203715, longitude: 50.160374) let distance:CLLocationDistance = currentLocation.distanceFromLocation(targetLocation); print("两点间距离是:\(distance)")
通过方法:func locationManager(manager: CLLocationManager, didUpdateHeading newHeading: CLHeading)可以获取设备移动的方向,通过一组属性提供航向读数:
magneticHeading(磁场航向)和trueHeading(真实航向),如果航向为0.0,则前进方向为北;如果航向为90.0,则前进方向为东;如果航向为180.0,则前进方向为南;如果航向为270.0,则前进方向为西;只有打开定位服务才可以获得真实航向。
代码实现:
//获取方向 func locationManager(manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) { headingLabel.text = "\(newHeading.trueHeading) degrees (true), \(newHeading.magneticHeading)degrees (magnetic)" print( headingLabel.text) }
定位出现错误时会调用下面的委托方法:
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) { print(error) if let clErr = CLError(rawValue: error.code){ switch clErr { case .LocationUnknown: print("位置不明") case .Denied: print("允许检索位置被拒绝") case .Network: print("用于检索位置的网络不可用") default: print("未知的位置错误") } } else { print("其他错误") let alert = UIAlertView(title: "提示信息", message: "定位失败", delegate: nil, cancelButtonTitle: "确定") alert.show() } }
对于得到的定位信息我们需要把经纬度信息,反编码成一个地址,这里需要用到CLGeocoder类来实现地理反编码。
//地理信息反编码 @IBAction func reverseGeocode(sender: AnyObject) { let geocoder = CLGeocoder() var p:CLPlacemark? geocoder.reverseGeocodeLocation(currLocation, completionHandler: { (placemarks, error) -> Void in // 强制 成 简体中文 let array = NSArray(object: "zh-hans") NSUserDefaults.standardUserDefaults().setObject(array, forKey: "AppleLanguages") // 显示所有信息 if error != nil { print("reverse geodcode fail: \(error!.localizedDescription)") return } let pm = placemarks if (pm!.count > 0){ p = placemarks![0] print(p)//输出反编码信息 print("country = \(p?.country)") print("postalCode = \(p?.postalCode)") print("location = \(p?.location)") }else{ print("No Placemarks!") } }) }
//地理信息编码 @IBAction func locationBianMa () { //使用Google 服务进行地理编码 let geocoder = CLGeocoder() var p:CLPlacemark? geocoder.geocodeAddressString("北京海淀区北三环西路39号", completionHandler: { (placemarks, error) -> Void in if error != nil { print("reverse geodcode fail: \(error!.localizedDescription)") return } let pm = placemarks if (pm!.count > 0){ p = placemarks![0] print("Longitude = \(p?.location!.coordinate.longitude)") print("Latitude = \(p?.location!.coordinate.latitude)") print(p) }else{ print("No Placemarks!") } }) }
二、地图
通过MapKit可以把地图嵌入到视图中,MapKit框架主要提供了四个功能:显示地图、CLLocation和地址之间的转换、支持在地图上做标记、把一个位置解析成地址。
首先导入MapKit.framework框架,通过代码或者静态创建MKMapView对象,可以显示地图。
// MARK: - Map @IBOutlet var mainMapView: MKMapView! @IBAction func showMap() { //使用代码创建地图 // let mapView: MKMapView = MKMapView(frame: CGRectMake(0, 0, 320, 200)) // self.view.addSubview(mapView) //创建一个MKCoordinateSpan对象,设置地图的范围 越小越精确 let latDelta = 0.05 let longDelta = 0.05 let currentLocationSpan: MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta) //定义一个区域,坐标使用定位获取的当前坐标locationManager.location.coordinate let currentRegion: MKCoordinateRegion = MKCoordinateRegionMake(locationManager.location!.coordinate, currentLocationSpan) //设置显示区域 self.mainMapView.setRegion(currentRegion, animated: true) //设置地图显示类型,标准地图、卫星模式、混合模式。 self.mainMapView.mapType = MKMapType.Standard //标准地图 //设置代理 self.mainMapView.delegate = self //创建一个大头针对象 let objectAnnotation = MKPointAnnotation() //设置大头针显示位置,我们使用定位到的坐标 objectAnnotation.coordinate = locationManager.location!.coordinate //设置点击大头针之后显示的标题 objectAnnotation.title = "北京海淀" //设置点击大头针之后显示的描述 objectAnnotation.subtitle = "北三环西路" //添加大头针 self.mainMapView.addAnnotation(objectAnnotation) }
代理方法:
// MARK: - MKMapViewDelegate func mapView(mapView: MKMapView, regionWillChangeAnimated animated: Bool){ //地图的缩放级别发生改变时, } func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool){ //地图的缩放完毕触发 } func mapViewWillStartLoadingMap(mapView: MKMapView){ //开始装载地图 } func mapViewDidFinishLoadingMap(mapView: MKMapView){ //结束装载地图 } func mapViewDidFailLoadingMap(mapView: MKMapView, withError error: NSError){ //装载失败 } func mapViewWillStartRenderingMap(mapView: MKMapView){ //开始渲染下载的地图块时调用 } func mapViewDidFinishRenderingMap(mapView: MKMapView, fullyRendered: Bool){ //渲染下载的地图结束时调用 } //自定义大头针样式 func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView?{ if annotation is MKUserLocation { //return nil so map view draws "blue dot" for standard user location return nil } let reuseId = "pin" var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView if pinView == nil { //创建一个大头针视图 pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId) pinView!.canShowCallout = true pinView!.animatesDrop = true //设置大头针颜色 pinView!.pinColor = .Purple //设置大头针点注释视图的右侧按钮样式 pinView!.rightCalloutAccessoryView = UIButton(type: UIButtonType.DetailDisclosure) } else { pinView!.annotation = annotation } return pinView } func mapView(mapView: MKMapView, didAddAnnotationViews views: [MKAnnotationView]){ //添加注释视图 } func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl){ } func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView){ //点击大头针注释视图 } func mapView(mapView: MKMapView, didDeselectAnnotationView view: MKAnnotationView){ //取消点击大头针注释视图 } func mapViewWillStartLocatingUser(mapView: MKMapView){ //正在跟踪用户的位置 } func mapViewDidStopLocatingUser(mapView: MKMapView){ //停止跟踪用户的位置 } func mapView(mapView: MKMapView, didUpdateUserLocation userLocation: MKUserLocation){ //更新用户的位置 } func mapView(mapView: MKMapView, didFailToLocateUserWithError error: NSError){ //跟踪用户的位置 失败 } func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState){ //移动annotation位置时调用。newState为宏,表示几个状态。是否能移动位置在annotation中设置。 } func mapView(mapView: MKMapView, didChangeUserTrackingMode mode: MKUserTrackingMode, animated: Bool){ //改变UserTrackingMode } func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer{ //设置overlay的渲染 return MKOverlayRenderer() } func mapView(mapView: MKMapView, didAddOverlayRenderers renderers: [MKOverlayRenderer]) { //地图上加上了overlayRenderers后调用 }