为什么我的动画不适用于 SwiftUI 制作的指南针

问题描述 投票:0回答:1

我正在制作一个简单的指南针视图,其中仅包含视图的基本内容,我希望将其动画化。我正在使用我的物理设备(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)
    }
}
animation swiftui compass swiftui-animation
1个回答
0
投票

尝试这种方法,您可以将旋转和动画设置为

attach
, 如示例代码所示。您还需要适应
VStack
的变化, 即如示例所示将其设为
heading
@Binding var heading: CGFloat
(如果您计划在
@State var heading: CGFloat = 0.0
内进行更改)。
请注意,您必须调整 

CompassView

以防止其褪色。同时将

Text("\(-heading, ...)
重命名为
GaugeMarkerCompass
GaugeMarker

© www.soinside.com 2019 - 2024. All rights reserved.