如何在SwiftUI中使用onReceive从ObservedObject获取数据? [英] How can I get data from ObservedObject with onReceive in SwiftUI?

查看:39
本文介绍了如何在SwiftUI中使用onReceive从ObservedObject获取数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的SwiftUI应用中,每次值更改时,我都需要从ObservedObject获取数据.我知道我们可以使用.onReceive来做到这一点?我不太了解Apple的相关文档.我不知道该怎么办.

In my SwiftUI app, I need to get data from ObservedObject each time the value change. I understood that we could do that with .onReceive? I don't understand well the documentation of Apple about it. I don't know how I can do this.

我的代码:

import SwiftUI
import CoreLocation

struct Compass: View {
  
  @StateObject var location = LocationManager()
  @State private var angle: CGFloat = 0
  
  var body: some View {
    VStack {
      Image("arrow")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(width: 300, height: 300)
        .modifier(RotationEffect(angle: -CGFloat(self.angle.degreesToRadians)))
        .onReceive(location, perform: {
          withAnimation(.easeInOut(duration: 1.0)) {
            self.angle = self.location.heading
          }
        })
      
      Text(String(self.location.heading.degreesToRadians))
        .font(.system(size: 20))
        .fontWeight(.light)
        .padding(.top, 15)
    }
  }
}

struct RotationEffect: GeometryEffect {
  var angle: CGFloat

  var animatableData: CGFloat {
    get { angle }
    set { angle = newValue }
  }

  func effectValue(size: CGSize) -> ProjectionTransform {
    return ProjectionTransform(
      CGAffineTransform(translationX: -150, y: -150)
        .concatenating(CGAffineTransform(rotationAngle: angle))
        .concatenating(CGAffineTransform(translationX: 150, y: 150))
    )
  }
}

在LocationManager类中,我有一个标题为Published的变量,这是我要检查的变量.

In my LocationManager class, I have a heading Published variable, this is the variable I want check.

每次箭头移动时,每次更改航向值时我都需要获取数据以创建动画.对于某些原因,我需要使用CGAffineTransform.

I need to get data each time the value of heading change to create an animation when my arrow move. For some raisons I need to use CGAffineTransform.

推荐答案

首先,在您的视图中,您需要请求HeadingProvider开始更新标题.您需要侦听objectWillChange通知,该闭包具有一个参数,它是ObservableObject上设置的新值.

First in your view you need to request the HeadingProvider to start updating heading. You need to listen to objectWillChange notification, the closure has one argument which is the new value that is being set on ObservableObject.

我对您的指南针做了一些改动:

I have changed your Compass a bit:

struct Compass: View {

  @StateObject var headingProvider = HeadingProvider()
  @State private var angle: CGFloat = 0

  var body: some View {
    VStack {
      Image("arrow")
        .resizable()
        .aspectRatio(contentMode: .fit)
        .frame(width: 300, height: 300)
        .modifier(RotationEffect(angle: angle))
        .onReceive(self.headingProvider.objectWillChange) { newHeading in
            withAnimation(.easeInOut(duration: 1.0)) {
                self.angle = newHeading
            }
        }

      Text(String("\(angle)"))
        .font(.system(size: 20))
        .fontWeight(.light)
        .padding(.top, 15)
    }   .onAppear(perform: {
            self.headingProvider.updateHeading()
        })
  }
}

我写了一个HeadingProvider示例:

I have written an example HeadingProvider:

public class HeadingProvider: NSObject, ObservableObject {
    
    public let objectWillChange = PassthroughSubject<CGFloat,Never>()
    
    public private(set) var heading: CGFloat = 0 {
        willSet {
            objectWillChange.send(newValue)
        }
    }
    
    private let locationManager: CLLocationManager
    
    public override init(){
        self.locationManager = CLLocationManager()
        super.init()
        self.locationManager.delegate = self
    }
    
    public func updateHeading() {
        locationManager.startUpdatingHeading()
    }
}

extension HeadingProvider: CLLocationManagerDelegate {
    
    public func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
        DispatchQueue.main.async {
            self.heading = CGFloat(newHeading.trueHeading)
        }
    }
}

请记住,您需要处理读取用户位置的权限请求,并且需要在某个时候调用stopUpdatingHeading().

Remember you need to handle asking for permission to read user's location and you need to call stopUpdatingHeading() at some point.

这篇关于如何在SwiftUI中使用onReceive从ObservedObject获取数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆