Swift - 计算运动距离的功能实现(分别基于GPS、计步器)
一、基本介绍
有时我们需要计算从 A 点移动到 B 点的距离,或者开发一个计算跑步公里数的 APP。即点击开始统计后,可以实时计算出跑过的路程长度。这个功能通常有两种实现方法:一种是基于 GPS 定位实现(使用 CoreLocation)、另一种基于计步器实现(使用 CMPedometer)
1,二者的实现原理
- 计步器实现:使用 CMPedometer 可以查询近 7 天内任意时间段的步数信息(包括运动距离)。这样我们只需在开始统计的时候记下当前的时间,实时获取从该时间起所有的运动信息即可。
- GPS 实现:使用 CoreLocation 可以实时获取当前的定位数据。这样我们只需在开始时记下当前的坐标位置,然后每次更新时计算最新坐标同上一次坐标间的距离。所有距离相加即为总的运动距离。
2,二者的优缺点
- 计步器实现:相对来说精度会更高些,而且不受环境的影响。不过只能统计走路或跑步的距离,如果是骑自行车或开车的话就没法统计距离了。
- GPS 实现:不管是走路还是坐车,都是可以统计距离。但其受 GPS 信号强弱影响很大,比如在室内、或者周围有高大建筑的时候,计算出来的距离与实际情况会有较大的偏差。
二、样例实现
1,效果图
(1)点击“开始统计”按钮后,我们分别使用计步器和 GPS 定位来实时统计运动距离,并显示在界面上。
(2)使用计步器统计时,除了显示运动距离,这里还会显示对应的步数。
(3)使用 GPS 定位时,除了显示运动距离,这里还会显示出直线距离(即最开始位置与当前位置的距离)
(4)下面是我从地铁站走到公司的统计情况,大家可以对比下二者的差别。
2,info.plist 配置
为了能使用定位以及计步器,我们首先需要在 info.plist 里加入相关的描述信息:
1 2 3 4 5 6 | < key >NSMotionUsageDescription</ key > < string >需要获取计步器数据信息</ string > < key >NSLocationWhenInUseUsageDescription</ key > < string >前台需要获取GPS数据信息</ string > < key >NSLocationAlwaysUsageDescription</ key > < string >后台需要获取GPS数据信息</ string > |
3,样例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | import UIKit import MapKit import CoreMotion class ViewController : UIViewController , CLLocationManagerDelegate { //用来显示计步器统计信息 @IBOutlet weak var label1: UILabel ! //用来显示GPS统计信息 @IBOutlet weak var label2: UILabel ! //计步器对象 let pedometer = CMPedometer () //定位管理器 let locationManager = CLLocationManager () //最开始的坐标 var startLocation: CLLocation ! //上一次的坐标 var lastLocation: CLLocation ! //总共移动的距离(实际距离) var traveledDistance: Double = 0 override func viewDidLoad() { super .viewDidLoad() } //开始统计按钮点击 @IBAction func startButtonTap(_ sender: Any ) { let button = sender as ! UIButton if ( button.titleLabel?.text == "开始统计" ){ //开始获取步数计数据 startPedometerUpdates() //开始获取GPS数据 startLocationUpdates() //按钮改变 button.setTitle( "停止统计" , for : .normal) } else { self .pedometer.stopUpdates() self .locationManager.stopUpdatingLocation() //按钮改变 button.setTitle( "开始统计" , for : .normal) } } //开始获取步数计数据 func startPedometerUpdates() { label1.text = "" //判断设备支持情况 if CMPedometer .isStepCountingAvailable() { //初始化并开始实时获取数据 self .pedometer.startUpdates (from: Date (), withHandler: { pedometerData, error in //错误处理 guard error == nil else { print (error!) return } //获取各个数据 var text = "--- 计步器统计数据 ---\n" if let distance = pedometerData?.distance { text += "行走距离: \(distance)\n" } if let numberOfSteps = pedometerData?.numberOfSteps { text += "行走步数: \(numberOfSteps)\n" } //在线程中更新文本框数据 DispatchQueue .main.async{ self .label1.text = text } }) } else { self .label1.text = "\n当前设备不支持获取步数\n" return } } //开始获取GPS数据 func startLocationUpdates() { label2.text = "" startLocation = nil traveledDistance = 0 if CLLocationManager .locationServicesEnabled() { locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation locationManager.requestWhenInUseAuthorization() locationManager.startUpdatingLocation() locationManager.startMonitoringSignificantLocationChanges() locationManager.distanceFilter = 10 } } //定位数据更新 func locationManager(_ manager: CLLocationManager , didUpdateLocations locations: [ CLLocation ]) { if startLocation == nil { startLocation = locations.first } else if let location = locations.last { //获取各个数据 traveledDistance += lastLocation.distance(from: location) let lineDistance = startLocation.distance(from: locations.last!) var text = "--- GPS统计数据 ---\n" text += "实时距离: \(traveledDistance)\n" text += "直线距离: \(lineDistance)\n" label2.text = text } lastLocation = locations.last } override func didReceiveMemoryWarning() { super .didReceiveMemoryWarning() } } |

航哥- 这个GPS一直在后台活动吗???