我正在制作一个简单的指南针视图,其中仅包含视图的基本内容,我希望将其动画化。我正在使用我的物理设备(iPhone 13 PRO)的指南针。所以,一切似乎都很好 - 标题是正确的,视图正在旋转,但是......动画不起作用,实际上任何动画类型都不起作用。但是如果我用它来旋转整个 ZStack 就可以了。一旦我尝试旋转仪表标记,它就不起作用了。请看下面的代码:
//
// CompassView.swift
// ExtasyCompleteNavigation
//
// Created by Vasil Borisov on 20.08.23.
//
import SwiftUI
struct CompassView: View {
var heading: CGFloat
var body: some View {
VStack{
ZStack{
GeometryReader{ geometry in
let width = geometry.size.width
let height = geometry.size.height
let fontSize = width/13
//compass background
Circle()
//compass heading display and direction
Text("\(-heading,specifier: "%.0f")°\n\(displayDirection())")
.font(Font.custom("AppleSDGothicNeo-Bold", size: width/13))
.foregroundColor(.white)
.position(x: width/2, y:height/2)
//compass degree ring
Group{
MyShape(sections: 12, lineLengthPercentage: 0.15)
.stroke(Color.white, style: StrokeStyle(lineWidth: 5))
MyShape(sections: 360, lineLengthPercentage: 0.15)
.stroke(Color.white, style: StrokeStyle(lineWidth: 2))
//compass arrow
Text("▼")
.font(Font.custom("AppleSDGothicNeo-Bold", size: fontSize))
.position(x:width/2, y: height/200 )
.foregroundColor(.red)
PseudoBoat()
.stroke(lineWidth: 4)
.foregroundColor(.white)
.scaleEffect(x: 0.30, y: 0.55, anchor: .top)
.offset(y: geometry.size.height/5)
}
//heading values
ForEach(GaugeMarkerCompass.labelSet()) { marker in
CompassLabelView(marker: marker, geometry: geometry)
.position(CGPoint(x: geometry.size.width / 2, y: geometry.size.height / 2))
}
.rotationEffect(.init(degrees: heading))
.animation(Animation.easeInOut(duration: 3), value: heading)
}.aspectRatio(1, contentMode: .fit)
}
}
}
//function can be moved in a structure with the rest of the tools in swift file
func displayDirection() -> String {
switch heading {
case 0:
return "N"
case 90:
return "E"
case 180:
return "S"
case 270:
return "W"
case 90..<180:
return "SE"
case 180..<270:
return "SW"
case 270..<360:
return "NW"
default:
return "NE"
}
}
//to be moved to a swift file and keep it separate
public struct CompassLabelView: View {
let marker: GaugeMarker
let geometry: GeometryProxy
@State var fontSize: CGFloat = 12
@State var paddingValue: CGFloat = 100
public var body: some View {
VStack {
Text(marker.label)
.foregroundColor(Color.gray)
.font(Font.custom("AppleSDGothicNeo-Bold", size: geometry.size.width * 0.05))
.rotationEffect(Angle(degrees: 0))
.padding(.bottom, geometry.size.width * 0.72)
}.rotationEffect(Angle(degrees: marker.degrees))
.onAppear {
paddingValue = geometry.size.width * 0.72
fontSize = geometry.size.width * 0.07
}
}
}
struct GaugeMarkerCompass: Identifiable, Hashable {
let id = UUID()
let degrees: Double
let label: String
init(degrees: Double, label: String) {
self.degrees = degrees
self.label = label
}
// adjust according to your needs
static func labelSet() -> [GaugeMarker] {
return [
GaugeMarker(degrees: 0, label: "N"),
GaugeMarker(degrees: 30, label: "30"),
GaugeMarker(degrees: 60, label: "60"),
GaugeMarker(degrees: 90, label: "E"),
GaugeMarker(degrees: 120, label: "120"),
GaugeMarker(degrees: 150, label: "150"),
GaugeMarker(degrees: 180, label: "S"),
GaugeMarker(degrees: 210, label: "210"),
GaugeMarker(degrees: 240, label: "240"),
GaugeMarker(degrees: 270, label: "W"),
GaugeMarker(degrees: 300, label: "300"),
GaugeMarker(degrees: 330, label: "330")
]
}
}
}
struct CompassView_Previews: PreviewProvider {
static var previews: some View {
CompassView(heading: 0)
.background(.white)
}
}