简体   繁体   中英

SwiftUI - Picker binding not updating when picker changes

I have a picker in my view as a segmented picker. Whenever I change the picker by sliding it, it does not update/print out the update. If I tap on it, it changes/updates. Want it to update when I slide it from one option to the other one. I also tried it with a.tag modifier instead of.id, and neither work:(

private let options = ["option1","option2"]

 @State private var urlMode = 0 {
        didSet {
            print("url mode set to \(urlMode)")
            
        }
    }

var url: String {
            if urlMode == 0 {
               return "www.google.com"
            } else {
               return "www.yahoo.com"
            }
        }

Return ZStack {

 Picker("", selection: $urlMode) {
                    ForEach(0..<options.count) { index in
                        Text(options[index])
                            .id(index)
                    }
                }
                .pickerStyle(SegmentedPickerStyle())
                .padding(.bottom, K.ScreenSize.screenWidth / 50)
                .padding(.horizontal)
                .onTapGesture {
                    if urlMode == 0 {
                        urlMode = 1
                    } else {
                        urlMode = 0
                    }
                }
}

It turns out the value was being set, but it wasn't updating/running the "didSet" portion of my @State var...an easy way for me to tell was to add a Text above my Picker like so:

Text("selection: \(options[urlMode])")

As I changed the picker, this value updated...so, for some reason, the didSet isn't printing, but it is indeed functioning properly...

If you are reading this and need another method to run code when this changes, either use jnpdx's answer above, or use a.onChange modifier to your Picker (make sure use it as-is and not as a binding/with a $):

.onChange(of: urlMode) { value in
                    //code to run
                }

There are a number of ways to achieve the link you're looking for. I recommend an ObservableObject with a @Published property, which you can observe with onReceive to do your print statement.

The tag is now working with the ForEach as well:

class ViewModel : ObservableObject {
    let options = ["option1","option2"]
    @Published var urlMode = 0
}

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()
    
    var url: String {
        if viewModel.urlMode == 0 {
            return "www.google.com"
        } else {
            return "www.yahoo.com"
        }
    }
    
    var body: some View {
        ZStack {
            Picker("", selection: $viewModel.urlMode) {
                ForEach(Array(viewModel.options.enumerated()), id: \.1.self) { (index,option) in
                    Text(option).tag(index)
                }
            }
            .pickerStyle(SegmentedPickerStyle())
            .padding(.horizontal)
        }.onReceive(viewModel.$urlMode) { (mode) in
            print("url mode set to \(mode)")
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM