返回 导航

Swift

hangge.com

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

作者:hangge | 2017-08-04 08:10

一、基本介绍

有时我们需要计算从 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 里加入相关的描述信息:
<key>NSMotionUsageDescription</key>
<string>需要获取计步器数据信息</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>前台需要获取GPS数据信息</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>后台需要获取GPS数据信息</string>

3,样例代码

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()

    }
}
源码下载hangge_1544.zip
评论

全部评论(1)

回到顶部