无法为 SwiftUI 计时器设置可变间隔 [英] Can't set Variable Interval for SwiftUI Timer
问题描述
我正在尝试在 SwiftUI 视图中自动显示一系列图像.我可以创建一个固定具有预定every"值的计时器并触发 .onReceive 中的视图更新关闭,但我无法构造一个具有间隔属性的计时器用户可以使用滑块进行调整.下面的代码适用于固定计时器.订阅正确触发,但我似乎找不到等效的.onReceive 订阅更新图像.我也尝试创建自己的TimerPublisher 但我遇到了同样的问题 - 我无法在不指定的情况下初始化它一个固定值.
I'm trying to automatically display a sequence of images in a SwiftUI view. I can create a fixed timer with a predetermined "every" value and trigger the view update in an .onReceive closure but I have not been able to construct a timer with a property for the interval that can be adjusted by the user with a slider. The code below works for the fixed timer. The subscription fires appropriately but I cannot seem to find an equivalent to .onReceive for a subscription to update the image. I also tried creating my own TimerPublisher but I had the same issue - I could not initialize it without specifying a fixed value.
我的观点:
struct ImageStream2: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(fetchRequest: DermPhoto.getAllDermPhotos()) var dermPhotos: FetchedResults<DermPhoto>
@State private var activeImageIndex = 0
@State private var animateSpeed: Double = 1.0
@State private var startTimer = false
let timer = Timer.publish(every: 1.0, on: .main, in: .default).autoconnect()
@State private var mst: MyTimerSubscription!
var body: some View {
GeometryReader { geo in
VStack {
Text("Time Sequence")
.foregroundColor(.blue)
.font(.system(size: 25))
Image(uiImage: UIImage(data: self.dermPhotos[self.activeImageIndex].myImage!)!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: geo.size.width - 20, height: geo.size.width - 20, alignment: .center)
.cornerRadius(20)
.shadow(radius: 10, x: 10, y: 10)
.onReceive(self.timer) { t in
print("in fixed timer")
if self.startTimer {
self.activeImageIndex = (self.activeImageIndex + 1) % self.dermPhotos.count
}
}
Group {
HStack {
Text("0.5").foregroundColor(.blue)
Slider(value: self.$animateSpeed, in: 0.5...5.0, step: 0.5)
Text("5.0").foregroundColor(.blue)
}
.padding()
Text("Replay at: " + "\(self.animateSpeed) " + (self.animateSpeed == 1.0 ? "second" : "seconds") + " per frame")
.foregroundColor(.blue)
HStack {
Button(action: {
self.startTimer.toggle()
if self.startTimer {
self.mst = MyTimerSubscription(interval: 5.0)
} else {
self.mst.subscription.cancel()
}
}) {
ZStack {
RoundedRectangle(cornerRadius: 20)
.fill(Color.yellow)
.frame(width: 200, height: 40)
Text(self.startTimer ? "Stop" : "Start").font(.headline)
}
}
}
.padding()
}//group
}//top VStack
}.onDisappear{ self.startTimer = false }
}
}
和订阅文件:
class MyTimerSubscription {
let subscription: AnyCancellable
let interval: Double
init(interval: Double) {
subscription =
Timer.publish(every:interval, on:.main, in:.default)
.autoconnect()
.sink { _ in
print("in MyTimerSubscription print")
}
self.interval = interval
}
deinit {
subscription.cancel()
}
}
任何指导将不胜感激.Xcode 11.3 (11C29)
Any guidance would be appreciated. Xcode 11.3 (11C29)
推荐答案
创建一个 Observable Timer:
Create an Observable Timer:
class TimerWrapper : ObservableObject {
let willChange = PassthroughSubject<TimerWrapper, Never>()
@Published var timer : Timer!
func start(withTimeInterval interval: Double) {
self.timer?.invalidate()
self.timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in
self.willChange.send(self)
}
}
}
然后在视图中添加:
@State var timer = Timer.publish(every: 1.0, on: .main, in: .default).autoconnect()
@State private var animateSpeed: Double = 1.0
然后是图像:
.onReceive(self.timer) { t in
if self.startTimer {
if self.timerToggle {
self.activeImageIndex = (self.activeImageIndex + 1) % self.dermPhotos.count
}
self.goTimerAnimation.toggle() //changes the shape of the frame
self.timerToggle.toggle()
self.pct.toggle() //changes the size of the frame
}
}//onReceive
在按钮动作中:
self.timer = Timer.publish(every: self.animateSpeed, on: .main, in: .default).autoconnect()
这篇关于无法为 SwiftUI 计时器设置可变间隔的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!