SwiftUI 在列表滚动期间停止更新
Posted
技术标签:
【中文标题】SwiftUI 在列表滚动期间停止更新【英文标题】:SwiftUI stops updates during scrolling of List 【发布时间】:2020-04-02 09:15:08 【问题描述】:在 SwiftUI 中给定一个列表,一旦开始平移,列表中视图的更新似乎会暂停,直到滚动停止。有没有办法防止这种情况发生?
考虑以下代码:
class Model: ObservableObject, Identifiable
@Published var offset: CGFloat = 0
let id = UUID()
private var timer: Timer!
init()
timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: _ in
self.update()
)
func update()
offset = CGFloat.random(in: 0...300)
struct ContentView: View
@ObservedObject var model1 = Model()
@ObservedObject var model2 = Model()
@ObservedObject var model3 = Model()
@ObservedObject var model4 = Model()
var body: some View
List
ForEach([model1, model2, model3, model4])
Rectangle()
.foregroundColor(.red)
.frame(width: $0.offset, height: 30, alignment: .center)
.animation(.default)
将导致这种行为:
【问题讨论】:
我不确定,但我认为 SwiftUI 不可能。它可能适用于 UIKit... 【参考方案1】:您可以像 Asperi 的回答那样使用 GCD,但这并不能解释为什么您的代码不起作用。
问题在于,当滚动视图跟踪您的触摸时,它以.tracking
模式运行运行循环。但是因为您使用scheduledTimer(withTimeInterval:repeats:block:)
创建了Timer
,所以Timer
仅设置为在.default
模式下运行。
您可以像这样将计时器添加到所有常见的运行循环模式(包括.tracking
):
RunLoop.main.add(timer, forMode: .common)
但我可能会改用 Combine 发布者,如下所示:
class Model: ObservableObject, Identifiable
@Published var offset: CGFloat = 0
let id = UUID()
private var tickets: [AnyCancellable] = []
init()
Timer.publish(every: 0.5, on: RunLoop.main, in: .common)
.autoconnect()
.map _ in CGFloat.random(in: 0...300)
.sink [weak self] in self?.offset = $0
.store(in: &tickets)
【讨论】:
【参考方案2】:这是由于Timer
和RunLoop
的性质。改用 GCD,如下面的方法
init()
var runner: (() -> ())?
runner =
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) [weak self] in
if let self = self
self.update()
runner?()
runner?()
【讨论】:
谢谢!非常有用的知识!以上是关于SwiftUI 在列表滚动期间停止更新的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 选择器在 ObservedObject 公共变量更新期间滚动时跳转