问题
I'm experiencing a strange behavior with wheel pickers embedded in a conditional subview. When the subview is shown, sometimes the values are not shown. Switching around between two conditional views, the values sometimes reappear. I've attached an animation showing the behavior and the full code. I can't find the reason for this.
Update: I've tried a lot of things to find the reason for this. Even after simplifying the revealing subform to just one single picker, replacing the foreach loop with hardcoded Text() entries, removing the framing and clipping on the picker, it still doesn't work.
import SwiftUI
fileprivate enum OpenSetting {
case none, start, end
}
struct ContentView: View {
@State private var openSetting = OpenSetting.none
@State private var startMinutes = 0
@State private var startSeconds = 10
@State private var endMinutes = 3
@State private var endSeconds = 0
var body: some View {
NavigationView {
Form {
// Start
TimeSetting(
title: "Start",
color: Color.yellow,
minutes: startMinutes,
seconds: startSeconds,
setting: .start,
openSetting: $openSetting
)
if openSetting == .start {
TimePicker(minutes: $startMinutes, seconds: $startSeconds)
}
// End
TimeSetting(
title: "End",
color: Color.green,
minutes: endMinutes,
seconds: endSeconds,
setting: .end,
openSetting: $openSetting
)
if openSetting == .end {
TimePicker(minutes: $endMinutes, seconds: $endSeconds)
}
}
.navigationBarTitle("Test")
.navigationBarItems(
trailing: Text("Start")
)
}
}
}
struct TimeSetting: View {
var title: String
var color: Color
var minutes: Int
var seconds: Int
fileprivate var setting: OpenSetting
fileprivate var openSetting: Binding<OpenSetting>
var body: some View {
HStack {
Text(title)
Spacer()
ZStack {
RoundedRectangle(cornerRadius: 4)
.fill(color)
Text(toTime(minutes: minutes, seconds: seconds))
}
.frame(width: 64, height: 32)
}
.contentShape(Rectangle())
.onTapGesture {
withAnimation() {
self.openSetting.wrappedValue = (self.openSetting.wrappedValue == self.setting) ? OpenSetting.none : self.setting
}
}
}
func toTime(minutes: Int, seconds: Int) -> String {
let timeString = String(format: "%02d", minutes) + ":" + String(format: "%02d", seconds)
return timeString
}
}
struct TimePicker: View {
var minutes: Binding<Int>
var seconds: Binding<Int>
var body: some View {
HStack() {
Spacer()
Picker(selection: minutes, label: EmptyView()) {
ForEach((0...9), id: \.self) { ix in
Text("\(ix)").tag(ix)
}
}.pickerStyle(WheelPickerStyle()).frame(width: 50).clipped()
Text("Min.")
Picker(selection: seconds, label: EmptyView()) {
ForEach((0...59), id: \.self) { ix in
Text("\(ix)").tag(ix)
}
}.pickerStyle(WheelPickerStyle()).frame(width: 50).clipped()
Text("Sec.")
Spacer()
}
}
}
回答1:
Using .id
for Picker
s seems helped. Tested with Xcode 11.2 / iOS 13.2.
var body: some View {
HStack() {
Spacer()
Picker(selection: minutes, label: EmptyView()) {
ForEach((0...9), id: \.self) { ix in
Text("\(ix)").tag(ix)
}
}.pickerStyle(WheelPickerStyle()).frame(width: 50).clipped()
.id(UUID().uuidString)
Text("Min.")
Picker(selection: seconds, label: EmptyView()) {
ForEach((0...59), id: \.self) { ix in
Text("\(ix)").tag(ix)
}
}.pickerStyle(WheelPickerStyle()).frame(width: 50).clipped()
.id(UUID().uuidString)
Text("Sec.")
Spacer()
}
}
回答2:
You can solve it with this way:
if openSetting == .start {
TimePicker1(minutes: $startMinutes, seconds: $startSeconds)
}
.......
if openSetting == .end {
TimePicker1(minutes: $endMinutes, seconds: $endSeconds).id(1)
}
One with id
, the other without id
.
来源:https://stackoverflow.com/questions/59224408/wheel-pickers-in-form-disappear-after-some-show-hide-cycles