根据设备俯仰、滚动和偏航旋转渐变 - 创建全息图/安全贴纸效果

mar*_*rkb 7 ios swift swiftui

我正在尝试在我正在开发的应用程序中实现一些有趣的添加,但似乎无法弄清楚如何让动画完全/正确地工作。

目前我有一些看起来像这样的东西:https ://i.imgur.com/95O1Wul.mp4

我想要实现的目标

我正在尝试创建一个全息图,就像您在一些闪亮的游戏卡一些钞票那些 VOID 贴纸上看到的那样。

我使用x设备的位置来确定是否移动渐变的起点和终点。我试图在脑海中弄清楚如何使用这些值来使渐变的起点和终点根据这些值进行移动。如果我合并其他轴,如果设备旋转,它将如何移动。

至于代码,目前我有:

查看模型

final class ContentViewModel: ObservableObject {
  @Published var gyroRotation = CMRotationRate()
  private let manager = CMMotionManager()
  private var timer: Timer?
 
  func startGyroscope() {
    if(manager.isGyroAvailable) {
      manager.gyroUpdateInterval = 1.0
      manager.startGyroUpdates()
      self.timer = Timer(fire: Date(), interval: (1.0/60.0), repeats: true, block: { timer in
        if let data = self.manager.gyroData {
          self.gyroRotation = data.rotationRate
        }
      })
      RunLoop.current.add(self.timer!, forMode: .default)
    }
  }

  func stopGyroscope() {
    if(self.timer != nil) {
      self.timer?.invalidate()
      self.timer = nil
      self.manager.stopGyroUpdates()
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

看法

struct ContentView: View {
  @StateObject var cm = ContentViewModel()
  var rotation: CMRotationRate { cm.gyroRotation }
  let gridItems = [
    GridItem(.flexible(minimum: 40, maximum: 90)),
    GridItem(.flexible(minimum: 40, maximum: 90)),
    GridItem(.flexible(minimum: 40, maximum: 90)),
    GridItem(.flexible(minimum: 40, maximum: 90)),
    GridItem(.flexible(minimum: 40, maximum: 90))
  ]

  var body: some View {
    LazyVGrid(columns: gridItems, spacing: 30) {
      ForEach(0..<60) { _ in
        LinearGradient(
          colors: [.red, .orange, .yellow, .blue, .purple, .green],
          startPoint: rotation.x > 0 ? .leading : .trailing,
          endPoint: rotation.x > 0 ? .trailing : .leading
        )
        .animation(.linear, value: rotation.x)
        .frame(width: 50, height: 50)
        .mask(
         Image("logo")
           .resizable()
           .scaledToFit()
           .opacity(0.3)
         )
       }
     }
     .padding(20)
     .onAppear { cm.startGyroscope() }
  }
}
Run Code Online (Sandbox Code Playgroud)

mar*_*rkb 2

继续这样做以使其工作,我意识到我不需要 LinearGradient 来制作动画,而是需要 Color 本身:

看法

struct CoreMotion: View {
    
    // -- where the data lives
    @ObservedObject var coreMotionVM = CoreMotionViewModel()
    
    let gridItems = [
        GridItem(), GridItem(), GridItem(), GridItem()
    ]
    
    // -- the view
    var body: some View {
        
        LazyVGrid(columns: gridItems, spacing: 5) {
            ForEach( 0 ..< 60 ) { _ in

                coreMotionVM.tintColour
                    .animation(
                        .easeInOut,
                        value: coreMotionVM.roll
                    )
                    .frame(width: 60, height: 60)
                    .padding(.vertical)
                    .mask(
                        Image("logo")
                            .resizable()
                            .scaledToFit()
                            .opacity(0.2)
                    )
            }
        }
        .padding(.horizontal)
        .padding(.top)
    }
}
Run Code Online (Sandbox Code Playgroud)

视图模型

final class CoreMotionViewModel: ObservableObject {
    
    // -- what we share
    @Published var roll: Double = 0.0
    
    // -- core motion manager
    private var manager: CMMotionManager

    // -- initialisation
    init() {
        
        // -- create the instance
        self.manager = CMMotionManager()
        
        // -- how often to get the data
        self.manager.deviceMotionUpdateInterval = 1/60
        
        // -- start it on the main thread
        self.manager.startDeviceMotionUpdates(to: .main) { motionData, error in
            
            // -- error lets get out of here
            guard error == nil else {
                print(error!)
                return
            }
            
            // -- update the data
            if let motionData = motionData {
                self.roll = motionData.attitude.roll
            }
        }
    }
    
    // cycle to the next point
    var tintColour: Color {
        switch roll {
            case ..<(-1.5):
                return .red
                
            case -1.5 ..< -1.0 :
                return .orange
                
            case -1.0 ..< -0.5 :
                return .yellow
                
            case -0.5 ..< 0.5 :
                return .green
                
            case 0.5 ..< 1.0 :
                return .blue
                
            case 1.0... :
                return .purple
                
            default:
                return .pink
        }
    }
}
Run Code Online (Sandbox Code Playgroud)