web-dev-qa-db-ja.com

SwiftUIのonReceiveでObservedObjectからデータを取得するにはどうすればよいですか?

私の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クラスには、Published変数という見出しがあります。これは、チェックしたい変数です。

矢印が動くときにアニメーションを作成するには、見出しの値が変わるたびにデータを取得する必要があります。一部の存在理由では、CGAffineTransformを使用する必要があります。

7
Guillaume

ObservableObjectで@Publishedを使用することを検討できます。その後、onreceiveは、location。$ headingを使用して電話を受けることができます。

観測可能なオブジェクトの場合、

class LocationManager: ObservableObject {
@Published var heading:Angle = Angle(degrees: 20)
}

受信には使用できます

struct Compass: View {

  @ObservedObject var location: LocationManager = LocationManager()
  @State private var angle: Angle = Angle(degrees:0)

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

上記は、オブジェクトの変更に対して追加の機能を実行する場合に役立ちます。多くの場合、location.headingを状態チェンジャーとして直接使用できます。そして、その下にアニメーションを付けます。そう

            .modifier(RotationEffect(angle: location.heading))
            .animation(.easeInOut)
0
Pbk

@LuLuGaGaが示すように実行できますが、これは少々簡単ではありません。 objectWillChangeはObservableObjectPublisherとして定義され、PassthroughSubject<CGFloat,Never>は今日機能しますが、将来的に機能するという保証はありません。

オブジェクトは単一のパブリッシャーに限定されないため、SwiftUI以外の目的で2番目または3番目を定義できます。例えば。:

class Observable<T>: ObservableObject, Identifiable {
    let id = UUID()
    let publisher = PassthroughSubject<T, Never>()
    var value: T {
        willSet { objectWillChange.send() }
        didSet { publisher.send(value) }
    }

    init(_ initValue: T) { self.value = initValue }
}

ObservableObjectをサブクラス化すると、objectWillChangeが正しく定義されるので、自分で行う必要はありません。

0
Michael Salmon