ios SwiftUI中更新值时,.repeatForever()不起作用

ct3nt3jp  于 2023-01-03  发布在  iOS
关注(0)|答案(1)|浏览(170)

我尝试在SwiftUI中制作一个空闲动画,如果屏幕上没有触摸3秒,就会触发该动画。(y偏移15)当3秒内没有触摸时,当发生触摸时,它会回到原来的位置。但问题是,当它回到原来的位置时,自动反转不会被触发。它看起来是这样的:

“启动”按钮:

struct GoLiveButton: View {

  @State private var animationOffset: CGFloat = 0
  @Binding var isIdle: Bool

  var body: some View {
    ZStack {
      Button(action: {} ) {
        Text("Go Live")
          .frame(width: 120, height: 40)
          .background(Color.black)
          .foregroundColor(.white)
          .clipShape(Capsule())
          .font(.system(size: 20))
          .shadow(color: .black, radius: 4, x: 4, y: 4)
      }
      .offset(y: animationOffset)
      .animation(.timingCurve(0.38, 0.07, 0.12, 0.93, duration: 2).repeatForever(autoreverses: true), value: isIdle)
      .animation(.timingCurve(0.38, 0.07, 0.12, 0.93, duration: 2), value: !isIdle)
    }
    .onAppear {
      self.isIdle = true
      self.animationOffset = 15
    }
    .onChange(of: isIdle) { newValue in
      if newValue {
        self.animationOffset = 15
      }
      else {
        self.animationOffset = 0
      }
    }
  }
}

以下是空闲视图:

struct StackOverflowView: View {

  @State private var timer: Timer?
  @State private var isIdle = false

  var body: some View {

    GeometryReader { geo in
      GoLiveButton(isIdle: $isIdle)
    }
    .onTapGesture {
      print("DEBUG: CustomTabView OnTapGesture Triggered")
      self.isIdle = false
      self.timer?.invalidate()
      self.timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { _ in
        self.isIdle = true
      }
    }
    .gesture(
      DragGesture().onEnded { _ in
        self.isIdle = false
        self.timer?.invalidate()
        self.timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { _ in
          self.isIdle = true
        }
      }
    )
  }
}
wydwbb8l

wydwbb8l1#

以下是不使用AnimatableData的方法:
我添加了第二个计时器,它每2秒通过偏移(0,-15,0,-15...)触发动画,永远重复。
如果isIdle变为false,我们只需要将offset设置为0,这个也会被动画化。我们重置所有的计时器。然后再次设置空闲计时器(3秒),当它启动时会启动动画计时器(2秒)。
(我还对GoLiveButton做了一些调整,使其自身包含所有相关状态,父视图只需控制isIdle

struct GoLiveButton: View {
    
    @Binding var isIdle: Bool
    @State private var timer: Timer?
    @State private var animationTimer: Timer?
    @State private var animationOffset: CGFloat = 0
    
    var body: some View {
        ZStack {
            Button(action: {} ) {
                Text("Go Live")
                    .frame(width: 120, height: 40)
                    .background(Color.black)
                    .foregroundColor(.white)
                    .clipShape(Capsule())
                    .font(.system(size: 20))
                    .shadow(color: .black, radius: 4, x: 4, y: 4)
            }
            .offset(y: animationOffset)
            .animation(.timingCurve(0.38, 0.07, 0.12, 0.93, duration: 2), value: animationOffset)
        }
        .onAppear {
            self.timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { _ in
                self.isIdle = true
                animationTimer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { _ in
                    animationOffset = (animationOffset == 15) ? 0 : 15
                }
            }
        }
        .onChange(of: isIdle) { newValue in
            if newValue == false {
                // reset all
                self.animationTimer?.invalidate()
                self.timer?.invalidate()
                animationOffset = 0
                
                self.timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: false) { _ in
                    self.isIdle = true
                    animationTimer = Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { _ in
                        animationOffset = (animationOffset == 15) ? 0 : 15
                    }
                }
            }
        }
    }
}

struct ContentView: View {
    
    @State private var isIdle = false
    
    var body: some View {
        
        ZStack {
            // for background tap only
            Color.gray.opacity(0.2)
                .onTapGesture {
                    print("tap")
                    self.isIdle = false
                }
            
            GoLiveButton(isIdle: $isIdle)
        }
    }
}

相关问题