首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我如何修正我的指南针应用程序,使一个完整的转弯时,走向359°从0°?

我如何修正我的指南针应用程序,使一个完整的转弯时,走向359°从0°?
EN

Stack Overflow用户
提问于 2019-11-18 16:58:50
回答 2查看 796关注 0票数 6

我正在swiftUI中创建一个指南针应用程序。它可以工作,但是当我添加动画以移动指南针时,下面的行为如下所示:

例如,当它从5°方向转到350°时,它决定做一个完整的转弯。这不是指南针的自然行为。

我的ContentView代码:

代码语言:javascript
运行
复制
import SwiftUI
import CoreLocation

struct ContentView: View {

  var locationManager = CLLocationManager()
  @ObservedObject var location: LocationProvider = LocationProvider()
  @State var angle: CGFloat = 0

  var body: some View {
    GeometryReader { geometry in
      VStack {
        Rectangle()
          .frame(width: 10, height: 30)
          .background(Color(.red))
          .foregroundColor(Color(.clear))
        Spacer()
        Text(String(Double(self.location.currentHeading).stringWithoutZeroFraction) + "°")
          .font(.system(size: 40))
          .foregroundColor(Color(.black))
        Spacer()
      }
      .frame(width: 300, height: 300, alignment: .center)
      .border(Color(.black))
      .onReceive(self.location.heading) { heading in
        withAnimation(.easeInOut(duration: 0.2)) {
          self.angle = heading
        }
      }
      .modifier(RotationEffect(angle: self.angle))
    }.background(Color(.white))
  }
}

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: -CGFloat(angle.degreesToRadians)))
        .concatenating(CGAffineTransform(translationX: 150, y: 150))
    )
  }
}

public extension CGFloat {
  var degreesToRadians: CGFloat { return self * .pi / 180 }
  var radiansToDegrees: CGFloat { return self * 180 / .pi }
}

public extension Double {
  var degreesToRadians: Double { return Double(CGFloat(self).degreesToRadians) }
  var radiansToDegrees: Double { return Double(CGFloat(self).radiansToDegrees) }

  var stringWithoutZeroFraction: String {
    return truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self)
  }
}

struct ContentView_Previews: PreviewProvider {
  static var previews: some View {
    ContentView()
  }
}

在这里,我使用CGAffineTransform旋转指南针和矩阵动画来解决这个问题。我认为这是可行的,因为当我在UIKit中使用这个方法时,这个问题并不存在。

我的LocationProvider代码:

代码语言:javascript
运行
复制
import SwiftUI
import CoreLocation
import Combine

public class LocationProvider: NSObject, CLLocationManagerDelegate, ObservableObject {

  private let locationManager: CLLocationManager
  public let heading = PassthroughSubject<CGFloat, Never>()

  @Published var currentHeading: CGFloat {
    willSet {
      heading.send(newValue)
    }
  }

  public override init() {
    currentHeading = 0
    locationManager = CLLocationManager()
    super.init()
    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.startUpdatingHeading()
    locationManager.requestWhenInUseAuthorization()
  }

  public func updateHeading() {
    locationManager.startUpdatingHeading()
  }

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

我如何解决这个问题?

EN

Stack Overflow用户

回答已采纳

发布于 2019-11-18 18:40:21

更新的:这将在旋转多次时起作用。感谢krjw指出了这个问题。

您没有理由需要您的angle属性停留在360°以内。而不是直接将heading分配给angle,而是计算差异并将其添加。

下面是一个有用的例子。在body属性之外的ContentView中,添加以下函数:

代码语言:javascript
运行
复制
// If you ever need the current value of angle clamped to 0..<360,
//   use clampAngle(self.angle)
func clampAngle(_ angle: CGFloat) -> CGFloat {
    var angle = angle
    while angle < 0 {
        angle += 360
    }
    return angle.truncatingRemainder(dividingBy: 360)
}

// Calculates the difference between heading and angle
func angleDiff(to heading: CGFloat) -> CGFloat {
    return (clampAngle(heading - self.angle) + 180).truncatingRemainder(dividingBy: 360) - 180
}

然后更改指定angle的行

代码语言:javascript
运行
复制
self.angle += self.angleDiff(to: heading)
票数 4
EN
查看全部 2 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58919537

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档