Как я могу получить данные из ObservedObject с помощью onReceive в SwiftUI? - PullRequest
0 голосов
/ 25 сентября 2019

В моем приложении SwiftUI мне нужно получать данные из ObservedObject при каждом изменении значения.Я понял, что мы можем сделать это с .onReceive?Я не очень хорошо понимаю документацию Apple об этом.Я не знаю, как я могу это сделать.

Мой код:

import SwiftUI
import CoreLocation

struct Compass: View {

  var locationManager = CLLocationManager()
  @ObservedObject var location: LocationManager = 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 у меня есть переменная заголовка Опубликованная, это переменная, которую я хочу проверить.

Мне нужно получать данные каждый раз, когда изменяется значение заголовка, чтобы создать анимацию при перемещении стрелки.Для некоторых случаев мне нужно использовать CGAffineTransform.

1 Ответ

1 голос
/ 25 сентября 2019

Сначала, по вашему мнению, вам нужно запросить HeadingProvider, чтобы начать обновление заголовка.Вам необходимо прослушать уведомление objectWillChange, у замыкания есть один аргумент, который является новым значением, устанавливаемым в ObservableObject.

Я немного изменил ваш компас:

struct Compass: View {

  @ObservedObject 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:

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 () в какой-то момент.

...