我在输出磁力计、加速度计和陀螺仪的数据时遇到了问题,使用SwiftUI的Core Motion。我假设我的问题与startMagnetometerUpdates()有关。
我已经尝试使用在stack overflow以及GitHub/google上找到的源代码。问题是我发现的所有代码都使用UIKit而不是SwiftUI。有没有可能在不使用UIKit的情况下实现这一点?
import CoreMotion
let motionManager = CMMotionManager()
var x = 0.0; var y = 0.0; var z = 0.0
func magnet() {
motionManager.magnetometerUpdateInterval = 1/60
motionManager.startMagnetometerUpdates()
if let magnetometerData = motionManager.magnetometerData {
x = magnetometerData.magneticField.x
y = magnetometerData.magneticField.y
z = magnetometerData.magneticField.z
}
}
struct Magnetometer: View {
var body: some View {
VStack {
Text("Magnetometer Data")
Text("X: \(x)")
Text("Y: \(y)")
Text("Z: \(z)")
}
}
}
struct Magnetometer_Previews: PreviewProvider {
static var previews: some View {
Magnetometer()
}
}输出应仅显示传感器的x、y和z值,并以1/60的间隔更新。每个值的当前输出是0.00000,这是因为我已经将每个变量设置为0。
发布于 2019-10-14 08:22:31
你的代码有几个问题。
您的第一个问题是,您需要在模型数据和视图之间建立绑定-通过创建绑定,视图将在模型更改时自动更新。
第二个问题是,您只能通过motionManager.magnetometerData访问一次磁力仪数据,而不是通过startMagnetometerUpdates(to:withHandler:)设置一个闭包来监视更新。
您可以使用Combine框架中的ObservableObject和视图中的@ObservedObject来创建适当的绑定。
首先创建一个类来包装您的运动管理器:
import Foundation
import Combine
import CoreMotion
class MotionManager: ObservableObject {
private var motionManager: CMMotionManager
@Published
var x: Double = 0.0
@Published
var y: Double = 0.0
@Published
var z: Double = 0.0
init() {
self.motionManager = CMMotionManager()
self.motionManager.magnetometerUpdateInterval = 1/60
self.motionManager.startMagnetometerUpdates(to: .main) { (magnetometerData, error) in
guard error == nil else {
print(error!)
return
}
if let magnetData = magnetometerData {
self.x = magnetData.magneticField.x
self.y = magnetData.magneticField.y
self.z = magnetData.magneticField.z
}
}
}
}这个类符合ObservableObject和@Publish的三个属性: x,y和z。
只需在磁力计更新闭包中为这些属性分配新的值,就会导致发布者触发并更新任何观察者。
现在,在您的视图中,您可以为运动管理器类声明一个@ObservedObject并绑定属性。
struct ContentView: View {
@ObservedObject
var motion: MotionManager
var body: some View {
VStack {
Text("Magnetometer Data")
Text("X: \(motion.x)")
Text("Y: \(motion.y)")
Text("Z: \(motion.z)")
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(motion: MotionManager())
}
}请注意,您需要在SceneDelegate.swift文件中传递一个MotionManager实例:
let contentView = ContentView(motion: MotionManager())发布于 2019-10-14 04:57:03
您可以使用Combine来构建一个类来提供数据:
import Combine
public class MagneicFieldProvider: NSObject, ObservableObject {
public let objectWillChange = PassthroughSubject<CMMagneticField,Never>()
public private(set) var magneticField: CMMagneticField = CMMagneticField() {
willSet {
objectWillChange.send(newValue)
}
}
deinit {
motionManager.stopMagnetometerUpdates()
}
private let motionManager: CMMotionManager
public override init(){
self.motionManager = CMMotionManager()
super.init()
motionManager.magnetometerUpdateInterval = 1/60
}
public func startUpdates() {
motionManager.startMagnetometerUpdates(to: OperationQueue.main) { this, that in
if let magneticField = self.motionManager.magnetometerData?.magneticField {
self.magneticField = magneticField
}
}
}
}然后在视图中使用它:
struct MagnetometerView: View {
@ObservedObject var magnetometer = MagneicFieldProvider()
var body: some View {
VStack(alignment: .leading) {
Text("Magnetometer Data")
Text("X: \(magnetometer.magneticField.x)")
Text("Y: \(magnetometer.magneticField.y)")
Text("Z: \(magnetometer.magneticField.z)")
} .onAppear(perform: { self.magnetometer.startUpdates() })
}
}https://stackoverflow.com/questions/58366799
复制相似问题