SwiftUI 选取器在 ObservedObject 公共变量更新期间滚动时跳转



目前正在创建一个 SwiftUI 应用程序,我在尝试解决 ObservedObject 和选取器的问题时遇到了困难。 我的内容视图:

struct ContentView: View {
@ObservedObject var timerManager = TimerManager()
...
var body: some View{
Circle()
.onTapGesture(perform: {  
self.timerManager.setTimerLength(seconds: self.settings.selectedSecondPickerIndex, minutes: self.settings.selectedMinutePickerIndex)
self.timerManager.start()
})
Picker(selection: self.$settings.selectedSecondPickerIndex, label: Text("")) {
ForEach(0 ..< 60) {
Text("(secondsToString(seconds: self.availableTimeInterval[$0]))")
}
}
}
...
}

计时器管理器管理计时器。 班级:

class TimerManager: ObservableObject {
@Published var secondsLeft : Int = -1
var secondsTotal : Int = -1
var timer = Timer()
func start() {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { timer in
if secondsLeft == 0 {
self.secondsLeft = secondsTotal
timer.invalidate()
}
else{
self.secondsLeft -= 1
}
}
RunLoop.current.add(timer, forMode: RunLoop.Mode.common)
}
func setTimerLength(seconds: Int, minutes: Int) {
let totalSeconds: Int = seconds + minutes * 60
secondsTotal = totalSeconds
secondsLeft = totalSeconds
}
...
}

我需要从 ContentView 访问计时器类的 secondsLeft 变量以显示剩余时间。当计时器运行时,秒左变量每秒更新一次,并且内容视图重新呈现。 问题是,当计时器运行时,我无法"轻弹"我的选择器,它总是重置,这里也指出:https://forums.developer.apple.com/thread/127218。但与那篇帖子不同的是,选择器的"选择"变量对问题没有任何影响。如果我从 secondsLeft 变量中删除@Public,一切正常(问题是我无法显示剩余时间(。

有人知道如何解决这个问题吗?

感谢您的回答!

这个问题可以通过自定义UIPickerView来解决:

import SwiftUI
struct ContentView: View {
@State var selection = 0
var body: some View {
VStack {
FixedPicker(selection: $selection, rowCount: 10) { row in
"(row)"
}
}
}
}
struct FixedPicker: UIViewRepresentable {
class Coordinator : NSObject, UIPickerViewDataSource, UIPickerViewDelegate {
@Binding var selection: Int

var initialSelection: Int?
var titleForRow: (Int) -> String
var rowCount: Int
func numberOfComponents(in pickerView: UIPickerView) -> Int {
1
}

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
rowCount
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
titleForRow(row)
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.selection = row
}

init(selection: Binding<Int>, titleForRow: @escaping (Int) -> String, rowCount: Int) {
self.titleForRow = titleForRow
self._selection = selection
self.rowCount = rowCount
}
}

@Binding var selection: Int

var rowCount: Int
let titleForRow: (Int) -> String
func makeCoordinator() -> FixedPicker.Coordinator {
return Coordinator(selection: $selection, titleForRow: titleForRow, rowCount: rowCount)
}
func makeUIView(context: UIViewRepresentableContext<FixedPicker>) -> UIPickerView {
let view = UIPickerView()
view.delegate = context.coordinator
view.dataSource = context.coordinator
return view
}

func updateUIView(_ uiView: UIPickerView, context: UIViewRepresentableContext<FixedPicker>) {

context.coordinator.titleForRow = self.titleForRow
context.coordinator.rowCount = rowCount
//only update selection if it has been changed
if context.coordinator.initialSelection != selection {
uiView.selectRow(selection, inComponent: 0, animated: true)
context.coordinator.initialSelection = selection
}
}
}

我在这里找到了这个解决方案: https://mbishop.name/2019/11/odd-behaviors-in-the-swiftui-picker-view/

希望这对每个人都有同样的问题!

最新更新