一、基本介绍
有时我们需要计算从 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()
}
}
|