附加到 Picker 时,onChange 不会触发
Posted
技术标签:
【中文标题】附加到 Picker 时,onChange 不会触发【英文标题】:onChange not firing when attached to a Picker 【发布时间】:2021-02-22 15:05:10 【问题描述】:我有一个由 3 部分组成的选择器,我试图让一个选择器的值基于另一个选择器的值。特别是在“Days”、“Weeks”等末尾添加/删除 s。我已经阅读了关于这种情况的类似帖子 (here),但是针对 ios 14+ 部署的建议 Apple 解决方案不起作用。鉴于另一个问题主要关注 14 岁之前的解决方案,我认为开始一个新问题会更有帮助。
谁能解释为什么永远不会调用 .onChange应该。
非常规的初始化只是为了封装从更大项目中删除的代码。 此外,我在下面的代码中注释掉了第三个选择器的 .id,但如果剩下的唯一问题是第三个选择器更新更改,则可以取消注释。
import SwiftUI
enum EveryType:String, Codable, CaseIterable, Identifiable
case every="Every"
case onceIn="Once in"
var id: EveryType self
var description:String
get
return self.rawValue
enum EveryInterval:String, Codable, CaseIterable, Identifiable
case days = "Day"
case weeks = "Week"
case months = "Month"
case years = "Year"
var id: EveryInterval self
var description:String
get
return self.rawValue
struct EventItem
var everyType:EveryType = .onceIn
var everyInterval:EveryInterval = .days
var everyNumber:Int = Int.random(in:1...3)
struct ContentView: View
init(eventItem:Binding<EventItem> = .constant(EventItem()))
_eventItem = eventItem
@Binding var eventItem:EventItem
@State var intervalId:UUID = UUID()
var body: some View
GeometryReader geometry in
HStack
Picker("", selection: self.$eventItem.everyType)
ForEach(EveryType.allCases)
type in Text(type.description)
.pickerStyle(WheelPickerStyle())
.frame(width: geometry.size.width * 0.3, height:100)
.compositingGroup()
.padding(0)
.clipped()
Picker("", selection: self.$eventItem.everyNumber
)
ForEach(1..<180, id: \.self) number in
Text(String(number)).tag(number)
//The purpase of the == 1 below is to only fire if the
// everyNumber values changes between being a 1 and
// any other value.
.onChange(of: self.eventItem.everyNumber == 1) _ in
intervalId = UUID() //Why won't this ever happen?
.pickerStyle(WheelPickerStyle())
.frame(width: geometry.size.width * 0.25, height:100)
.compositingGroup()
.padding(0)
.clipped()
Picker("", selection: self.$eventItem.everyInterval)
ForEach(EveryInterval.allCases) interval in
Text("\(interval.description)\(self.eventItem.everyNumber == 1 ? "" : "s")")
.pickerStyle(WheelPickerStyle())
.frame(width: geometry.size.width * 0.4, height:100)
.compositingGroup()
.clipped()
//.id(self.intervalId)
.frame(height:100)
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView(eventItem: .constant(EventItem()))
【问题讨论】:
【参考方案1】:试试下面的
.onChange(of: self.eventItem.everyNumber) newValue in
if newValue == 1
intervalId = UUID()
但这也可能取决于您如何使用此视图,因为.constant
绑定永远不会改变。
【讨论】:
我的问题是我试图在预览中调试它。正如您所评论的,预览是在提供的 eventItem 周围使用 .constant() 生成的,因此 onChange 没有触发。【参考方案2】:对于 Picker,它的 item 数据类型必须符合 Identifiable 并且我们必须将 item 的属性作为 "id" 传递给 "tag" 修饰符,以让 Picker 触发选择并在 Binding 变量中返回该属性与选择。
例如:
Picker(selection: $selected, label: Text(""))
ForEach(data)item in //data's item type must conform Identifiable
HStack
//item view
.tag(item.property)
.onChange(of: selected, perform: value in
//handle value of selected here (selected = item.property when user change selection)
)
//天哪!我花了整整一天的时间才发现这个
【讨论】:
【参考方案3】:上面 Thang Dang 的回答对我很有帮助。我不知道如何使我的标签符合 Identifiable,但将我的标签从 tag(1) 更改为字符串,如下面的 SwiftUI 代码所示。当 Picker 设置为 Icosahedron(我在 setShape 上的断点从未触发)时,其中只有一个数字的标签不会导致任何事情发生,但其他三个导致正确的形状被传递给 setShape。
//设置当前Shape
func setShape(value: String) 打印(值)
@State var shapeSelected = "Cube"
VStack
Picker(selection: $shapeSelected, label: Text("$\(shapeSelected)"))
Text("Cube").tag("Cube")
Text("Simplex").tag("Simplex")
Text("Pentagon (3D)").tag("Pentagon")
Text("Icosahedron").tag(1)
.onChange(of: shapeSelected, perform: tag in
setShape(value: "\(tag)")
)
【讨论】:
以上是关于附加到 Picker 时,onChange 不会触发的主要内容,如果未能解决你的问题,请参考以下文章
当 @State var 基于 Picker 选择发生变化时,一个视图不会重新呈现
onchange 在被 javascript 修改时不会触发
Android Contact Picker Intent 总是返回空的附加信息
TinyMCE4 file_picker_callback - 返回附加参数