Swift - 计算运动距离的功能实现(分别基于GPS、计步器)

时间:2024-06-01 07:39:08

一、基本介绍

有时我们需要计算从 A 点移动到 B 点的距离,或者开发一个计算跑步公里数的 APP。即点击开始统计后,可以实时计算出跑过的路程长度。这个功能通常有两种实现方法:一种是基于 GPS 定位实现(使用 CoreLocation)、另一种基于计步器实现(使用 CMPedometer

1,二者的实现原理

  • 计步器实现:使用 CMPedometer 可以查询近 7 天内任意时间段的步数信息(包括运动距离)。这样我们只需在开始统计的时候记下当前的时间,实时获取从该时间起所有的运动信息即可。
  • GPS 实现:使用 CoreLocation 可以实时获取当前的定位数据。这样我们只需在开始时记下当前的坐标位置,然后每次更新时计算最新坐标同上一次坐标间的距离。所有距离相加即为总的运动距离。

2,二者的优缺点

  • 计步器实现:相对来说精度会更高些,而且不受环境的影响。不过只能统计走路或跑步的距离,如果是骑自行车或开车的话就没法统计距离了。
  • GPS 实现:不管是走路还是坐车,都是可以统计距离。但其受 GPS 信号强弱影响很大,比如在室内、或者周围有高大建筑的时候,计算出来的距离与实际情况会有较大的偏差。

二、样例实现

1,效果图

(1)点击“开始统计”按钮后,我们分别使用计步器和 GPS 定位来实时统计运动距离,并显示在界面上。
(2)使用计步器统计时,除了显示运动距离,这里还会显示对应的步数。
(3)使用 GPS 定位时,除了显示运动距离,这里还会显示出直线距离(即最开始位置与当前位置的距离)
(4)下面是我从地铁站走到公司的统计情况,大家可以对比下二者的差别。 
Swift - 计算运动距离的功能实现(分别基于GPS、计步器)

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>
Swift - 计算运动距离的功能实现(分别基于GPS、计步器)

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 ViewControllerUIViewControllerCLLocationManagerDelegate {
 
    //用来显示计步器统计信息
    @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 asUIButton
        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()
 
    }
}
源码下载Swift - 计算运动距离的功能实现(分别基于GPS、计步器)hangge_1544.zip