简体   繁体   English

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

[英].repeatForever() does not work when value is updated in SwiftUI

I'm trying to make an idle animation in SwiftUI that gets triggered if there's no touch in the screen for 3 seconds.我正在尝试在SwiftUI中创建一个空闲的 animation,如果屏幕上没有触摸 3 秒,它就会被触发。 I made a little animation that goes up and down (y offset 15) when there's no touch for 3 seconds and goes back to its original position when a touch occurs.我做了一个小的 animation,当没有触摸 3 秒时,它会上下移动(y 偏移量 15),并在发生触摸时返回到其原始的 position。 But the thing is, when it goes to its original positon, autoreverses doesn't get triggered.但问题是,当它回到原来的位置时,自动反转不会被触发。 Here's how it looks like:它是这样的:

唔

Go Live button: Go 直播按钮:

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
      }
    }
  }
}

Here is the idle view:这是空闲视图:

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
        }
      }
    )
  }
}

Here is an approach without AnimatableData:这是一种没有 AnimatableData 的方法:

I added a second timer that just triggers the animations by offset (0, -15, 0, -15...) every 2 seconds, repeating forever.我添加了第二个计时器,它每 2 秒通过偏移量 (0、-15、0、-15...) 触发动画,永远重复。

If isIdle changes to false, we just set offset to 0, and this will be animated too.如果isIdle变为 false,我们只需将 offset 设置为 0,这也会被激活。 We reset all timers.我们重置所有计时器。 And again set the idle timer (3 secs) which when fires will start the animation timer (2 secs).并再次设置空闲计时器(3 秒),当触发时将启动 animation 计时器(2 秒)。 voila.瞧。

(I also restructured the GoLiveButton a little bit so it holds all relevant states in itself, and the parent view only has to control isIdle ) (我还对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)
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当我使用 SwiftUI 绘制自定义标签栏时,垫片不起作用 - Spacer does not work when I draw custom tab bar with SwiftUI SwiftUI 在 NavigationLink 中设置 editMode 时 EditButton() 不起作用 - SwiftUI EditButton() does not work when set editMode in NavigationLink 从 SwiftUI 中的 @ObservedObject 获取更新的值 - Getting the updated value from @ObservedObject in SwiftUI SwiftUI 在视图中注入实体时预览不适用于核心数据 - SwiftUI Preview Does Not Work with Core Data when Entity Injected in View SwiftUI @ObservedObject 不会在异步获取图像时更新 - SwiftUI @ObservedObject does not get updated on Async fetch of the image 为什么当我的基础数据源更新时 SwiftUI 会自动向后导航,如何避免这种行为? - Why does SwiftUI automatically navigate backwards when my underlying data source is updated and how can I avoid this behavior? 为什么 Property Observer 不适用于 SwiftUI 中的 Picker - Why Property Observer does not work for Picker in SwiftUI iPad 中的 NavigationView 弹出框在 SwiftUI 中无法正常工作 - NavigationView in iPad popover does not work properly in SwiftUI SwiftUI NavigationView 与列表编程导航不起作用 - SwiftUI NavigationView with List programmatic navigation does not work 在SwiftUI中更新其他变量时如何修改/重置@State - How to modify/reset @State when other variables are updated in SwiftUI
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM