一、定位
1、经纬度
latitude:纬度
longitude:经度
--------------------------------ViewController.swift-------------------------------
import UIKit
import CoreLocation
class ViewController: UIViewController {
//懒加载创建一个位置管理者
lazy var locationManager: CLLocationManager = {
let locationM = CLLocationManager()
locationM.delegate = self
//在ios8.0之后,需要主动请求授权
//一定不要忘记在info.plist文件中配置key
if #available(iOS 8.0, *) {
locationM.requestWhenInUseAuthorization()
// locationM.requestAlwaysAuthorization()
//设置过滤距离
//意味着每隔100米定位一次
//如果最新的位置距离上一次的位置之间的直线物理距离大于这个数字,就会通过代理告诉我们
locationM.distanceFilter = 100.0
//定位的精确度
// kCLLocationAccuracyBestForNavigation//最适合导航
// kCLLocationAccuracyBest;//最好的
// kCLLocationAccuracyNearestTenMeters//附近10米
// kCLLocationAccuracyHundredMeters;//附近100米
// kCLLocationAccuracyKilometer;//附近1000米
// kCLLocationAccuracyThreeKilometers;//附近3000米
//开发经验:如果精确度越高就越耗电,并且定位时间越长;为了省电尽量在满足需求的情况下低精确度。
locationM.desiredAccuracy = kCLLocationAccuracyBest
if #available(iOS 9.0, *){
//默认情况下只能在前台获取用户位置信息,如果想要在后台获取需要勾选后台模式location updates,但是如果当前的系统版本是iOS9.0+,那么需要额外的执行以下方法
//如果设置这样的属性为true,那么必须勾选后台模式,否则会崩溃。(和iOS8.0的后台定位区别就在于下面这句代码)
locationM.allowsBackgroundLocationUpdates = true
}
}
return locationM
}()
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
//开始获取用户位置信息
// self.locationManager.startUpdatingLocation()
//计算两个经纬度之间的物理距离
let latitude: CLLocationDegrees = 21.123
let longitude: CLLocationDegrees = 121.234
let loc1: CLLocation = CLLocation(latitude: latitude, longitude: longitude)
let latitude2: CLLocationDegrees = 22.123
let longitude2: CLLocationDegrees = 121.234
let loc2: CLLocation = CLLocation(latitude: latitude2, longitude: longitude2)
let distance = loc1.distance(from: loc2)
print(distance)
}
}
extension ViewController: CLLocationManagerDelegate {
//获取用户位置信息
// 参数1:位置管理者
// 参数2:位置数组
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//locations 位置数组,是按照时间的升序进行排序;如果要想获取最新的位置,只需要拿到数组的最后一个就好。
//coordinate:CLLocationCoordinate2D 经纬度结构体
//altitude: 海拔
//horizontalAccuracy:如果这个数字小于0,就代表位置数据无效
//verticalAccuracy:垂直精度,如果这个数字小于0,就代表海拔数据无效
//course:航向,0是相对于正北,0.0-359.9
//speed:速度
//distanceFromLocation:计算两个位置之间的物理距离
let location = locations.last
if (location?.horizontalAccuracy)! < 0{
print("位置数据无效")
return
}
location?.verticalAccuracy
print("已经获取到了位置信息")
}
/**如果当前的授权状态发生变化时调用
* manager:位置管理者
* status: 授权状态
*/
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case CLAuthorizationStatus.notDetermined:
print("用户没有决定")
case CLAuthorizationStatus.restricted:
print("受限制")
case CLAuthorizationStatus.authorizedAlways:
print("前后台定位授权")
case CLAuthorizationStatus.authorizedWhenInUse:
print("前台定位授权")
case CLAuthorizationStatus.denied:
if CLLocationManager.locationServicesEnabled(){
print("真正的被拒绝")
//如果以后再开发过程中,发现已经被用户拒绝了我们应该提醒用户
//这边只写跳转的关键代码
//注意:这个跳转只能在iOS8.0之后才能跳转到设置界面
if #available(iOS 8.0, *){
let url: NSURL? = NSURL(string: UIApplicationOpenSettingsURLString)
if UIApplication.shared.canOpenURL(url! as URL){
UIApplication.shared.openURL(url! as URL)
}
}
//如果想要在iOS8.0之前跳转到设置界面方法
//1.可以一步一步的截图告诉用户该怎么操作
//2.prefs:root=LOCATION_SERVICES
// guard let url: NSURL = NSURL(string: "prefs:root=LOCATION_SERVICES") else {
// return
// }
// if UIApplication.shared.canOpenURL(url as URL){
// UIApplication.shared.openURL(url as URL)
// }
}else {
print("请打开定位服务")
}
}
}
}
2、CLLocation的场景演练
import UIKit
import CoreLocation
class ViewController: UIViewController {
//记录上一次的位置
var lastLocation: CLLocation?
//懒加载创建一个位置管理者
lazy var locationManager: CLLocationManager = {
let locationM = CLLocationManager()
locationM.delegate = self
//在ios8.0之后,需要主动请求授权
//一定不要忘记在info.plist文件中配置key
if #available(iOS 8.0, *) {
locationM.requestWhenInUseAuthorization()
// locationM.requestAlwaysAuthorization()
//设置过滤距离
//意味着每隔100米定位一次
//如果最新的位置距离上一次的位置之间的直线物理距离大于这个数字,就会通过代理告诉我们
locationM.distanceFilter = 100.0
//定位的精确度
// kCLLocationAccuracyBestForNavigation//最适合导航
// kCLLocationAccuracyBest;//最好的
// kCLLocationAccuracyNearestTenMeters//附近10米
// kCLLocationAccuracyHundredMeters;//附近100米
// kCLLocationAccuracyKilometer;//附近1000米
// kCLLocationAccuracyThreeKilometers;//附近3000米
//开发经验:如果精确度越高就越耗电,并且定位时间越长;为了省电尽量在满足需求的情况下低精确度。
locationM.desiredAccuracy = kCLLocationAccuracyBest
if #available(iOS 9.0, *){
//默认情况下只能在前台获取用户位置信息,如果想要在后台获取需要勾选后台模式location updates,但是如果当前的系统版本是iOS9.0+,那么需要额外的执行以下方法
//如果设置这样的属性为true,那么必须勾选后台模式,否则会崩溃。(和iOS8.0的后台定位区别就在于下面这句代码)
locationM.allowsBackgroundLocationUpdates = true
}
}
return locationM
}()
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
//开始获取用户位置信息
self.locationManager.startUpdatingLocation()
//计算两个经纬度之间的物理距离
// let latitude: CLLocationDegrees = 21.123
// let longitude: CLLocationDegrees = 121.234
// let loc1: CLLocation = CLLocation(latitude: latitude, longitude: longitude)
//
// let latitude2: CLLocationDegrees = 22.123
// let longitude2: CLLocationDegrees = 121.234
// let loc2: CLLocation = CLLocation(latitude: latitude2, longitude: longitude2)
//
// let distance = loc1.distance(from: loc2)
// print(distance)
}
}
extension ViewController: CLLocationManagerDelegate {
//获取用户位置信息
// 参数1:位置管理者
// 参数2:位置数组
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//locations 位置数组,是按照时间的升序进行排序;如果要想获取最新的位置,只需要拿到数组的最后一个就好。
//coordinate:CLLocationCoordinate2D 经纬度结构体
//altitude: 海拔
//horizontalAccuracy:如果这个数字小于0,就代表位置数据无效
//verticalAccuracy:垂直精度,如果这个数字小于0,就代表海拔数据无效
//course:航向,0是相对于正北,0.0-359.9
//speed:速度
//distanceFromLocation:计算两个位置之间的物理距离
guard let location = locations.last else {
return
}
if location.horizontalAccuracy < 0{
print("位置数据无效")
return
}
/**CLLocation场景演练*/
//场景演示:打印当前用户的行走方向,偏离角度和对应的行走距离(例如:北偏东30度方向移动了8米)
//获取当前的方向
//course: 0.0 - 359.9 (北偏东,东偏南,南偏西,西偏北)
let courseStrArr = ["北偏东","东偏南","南偏西","西偏北"]
let index = Int(location.course) / 90
var courseStr = courseStrArr[index]
//计算偏离角度
let angle = location.course.truncatingRemainder(dividingBy: 90.0)
//判断是否是正方向
if Int(angle) == 0 {
let tempStr: NSString = courseStr as NSString
courseStr = tempStr.substring(to: 1)
}
//计算移动了多少米
var distance = 0.0
if lastLocation != nil {
distance = location.distance(from: lastLocation!)
}
lastLocation = location
//北偏东 30度 方向 移动了8米
print(courseStr,angle,"方向,移动了","\(distance)米")
}
/**如果当前的授权状态发生变化时调用
* manager:位置管理者
* status: 授权状态
*/
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case CLAuthorizationStatus.notDetermined:
print("用户没有决定")
case CLAuthorizationStatus.restricted:
print("受限制")
case CLAuthorizationStatus.authorizedAlways:
print("前后台定位授权")
case CLAuthorizationStatus.authorizedWhenInUse:
print("前台定位授权")
case CLAuthorizationStatus.denied:
if CLLocationManager.locationServicesEnabled(){
print("真正的被拒绝")
//如果以后再开发过程中,发现已经被用户拒绝了我们应该提醒用户
//这边只写跳转的关键代码
//注意:这个跳转只能在iOS8.0之后才能跳转到设置界面
if #available(iOS 8.0, *){
let url: NSURL? = NSURL(string: UIApplicationOpenSettingsURLString)
if UIApplication.shared.canOpenURL(url! as URL){
UIApplication.shared.openURL(url! as URL)
}
}
//如果想要在iOS8.0之前跳转到设置界面方法
//1.可以一步一步的截图告诉用户该怎么操作
//2.prefs:root=LOCATION_SERVICES
// guard let url: NSURL = NSURL(string: "prefs:root=LOCATION_SERVICES") else {
// return
// }
// if UIApplication.shared.canOpenURL(url as URL){
// UIApplication.shared.openURL(url as URL)
// }
}else {
print("请打开定位服务")
}
}
}
}
二、指南针效果的实现
1、磁力计
---------------------------指南针---------------------------
import UIKit
import CoreLocation
class ViewController: UIViewController {
@IBOutlet weak var compassView: UIImageView!
lazy var locationM: CLLocationManager = {
let locationM = CLLocationManager()
locationM.delegate = self
return locationM
}()
override func viewDidLoad() {
super.viewDidLoad()
//判断当前设备”磁力计传感器能不能用
if CLLocationManager.headingAvailable(){
//开始获取当前设备朝向
locationM.startUpdatingHeading()
}else{
print("你的设备当前不支持获取设备朝向")
}
}
}
extension ViewController:CLLocationManagerDelegate {
//当获取到当前设备朝向时调用
//manager:位置管理者
//newHeading:设备朝向对象
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
//判断数据能不能用
if newHeading.headingAccuracy < 0 {
return
}
//这里获取的是相对于磁北方向的"角度"
let angle = newHeading.magneticHeading
//把角度-->弧度
let hudu:CGFloat = CGFloat(angle/180.0 * Double.pi)
//反向旋转图片
//rotationAngle:弧度
UIView.animate(withDuration: 0.5) {
self.compassView.transform = CGAffineTransform(rotationAngle: -hudu)
}
}
}
三、监听进入或离开指定的区域
用模拟器试验,修改模拟器的位置来监听进入或离开区域
离开监听区域
进入监听区域
代码如下:
import UIKit
import CoreLocation
class ViewController: UIViewController {
//懒加载
lazy var locationM: CLLocationManager = {
let locationM = CLLocationManager()
locationM.delegate = self
//适配iOS8.0+请求授权,需要在info.plist配置key
locationM.requestAlwaysAuthorization()
return locationM
}()
override func viewDidLoad() {
super.viewDidLoad()
monitorRegion()
}
func monitorRegion(){
//监听区域
//0.判断能否监听区域
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
//1.创建一个区域
let center = CLLocationCoordinate2D(latitude: 12.123, longitude: 123.234)
var radius = 1000.0
if radius > locationM.maximumRegionMonitoringDistance{
radius = locationM.maximumRegionMonitoringDistance
}
//identifier标识,用来标记一个区域
let region: CLCircularRegion = CLCircularRegion(center: center, radius: radius, identifier: "region1")
//2.监听指定区域
locationM.startMonitoring(for: region)
}
}
}
extension ViewController:CLLocationManagerDelegate{
//进入指定区域
//manager: 位置管理者
//region: 区域
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("进入一个区域:" + region.identifier)
}
//离开指定区域
//manager:位置管理者
//region:区域
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("离开一个区域:" + region.identifier)
}
}
请求区域状态
import UIKit
import CoreLocation
class ViewController: UIViewController {
//懒加载
lazy var locationM: CLLocationManager = {
let locationM = CLLocationManager()
locationM.delegate = self
//适配iOS8.0+请求授权,需要在info.plist配置key
locationM.requestAlwaysAuthorization()
return locationM
}()
override func viewDidLoad() {
super.viewDidLoad()
monitorRegion()
}
func monitorRegion() {
//监听区域
//0.判断能否监听区域
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
//1.创建一个区域
let center = CLLocationCoordinate2D(latitude: 12.123, longitude: 123.234)
var radius = 1000.0
if radius > locationM.maximumRegionMonitoringDistance{
radius = locationM.maximumRegionMonitoringDistance
}
//identifier标识,用来标记一个区域
let region: CLCircularRegion = CLCircularRegion(center: center, radius: radius, identifier: "region1")
//2.监听指定区域
locationM.startMonitoring(for: region)
//3.监听请求区域的状态
locationM.requestState(for: region)
}
}
}
extension ViewController:CLLocationManagerDelegate{
//进入指定区域
//manager: 位置管理者
//region: 区域
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("进入一个区域:" + region.identifier)
}
//离开指定区域
//manager:位置管理者
//region:区域
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("离开一个区域:" + region.identifier)
}
//确定某个指定区域的状态后调用(用来监听请求区域的状态)
//manager: 位置管理者
//state:区域状态
//region:区域
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
if state == CLRegionState.inside{
print("在监听区域内")
}else if state == CLRegionState.outside{
print("在监听区域外部")
}else{
print("未知")
}
}
}