SwiftUI Picker onChange or equivalent?

后端 未结 7 1776
南旧
南旧 2020-12-01 09:31

I want to change some other unrelated @State variable when a Picker gets changed but there is no onChanged and it\'s not possible to p

相关标签:
7条回答
  • 2020-12-01 09:55

    I think this is simpler solution:

    @State private var pickerIndex = 0
    var yourData = ["Item 1", "Item 2", "Item 3"]
    
    // USE this if needed to notify parent
    @Binding var notifyParentOnChangeIndex: Int    
    
    var body: some View {
    
       let pi = Binding<Int>(get: {
    
                return self.pickerIndex
    
            }, set: {
    
                self.pickerIndex = $0
    
                // TODO: DO YOUR STUFF HERE
                // TODO: DO YOUR STUFF HERE
                // TODO: DO YOUR STUFF HERE
    
                // USE this if needed to notify parent
                self.notifyParentOnChangeIndex = $0
    
            })
    
       return VStack{
    
                Picker(selection: pi, label: Text("Yolo")) {
                    ForEach(self.yourData.indices) {
                        Text(self.yourData[$0])
                    }
                }
                .pickerStyle(WheelPickerStyle())
                .padding()
    
       }
    
    }
    
    0 讨论(0)
  • 2020-12-01 09:55

    First of all, full credit to ccwasden for the best answer. I had to modify it slightly to make it work for me, so I'm answering this question hoping someone else will find it useful as well.

    Here's what I ended up with (tested on iOS 14 GM with Xcode 12 GM)

    struct SwiftUIView: View {
        @State private var selection = 0
    
        var body: some View {
            Picker(selection: $selection, label: Text("Some Label")) {
                ForEach(0 ..< 5) {
                    Text("Number \($0)") }
            }.onChange(of: selection) { _ in
                print(selection)
            }
            
        }
    }
    

    The inclusion of the "_ in" was what I needed. Without it, I got the error "Cannot convert value of type 'Int' to expected argument type '()'"

    0 讨论(0)
  • 2020-12-01 09:57

    SwiftUI 1 & 2

    Use onReceive and Just:

    import Combine
    import SwiftUI
    
    struct ContentView: View {
        @State private var selection = 0
    
        var body: some View {
            Picker("Some Label", selection: $selection) {
                ForEach(0 ..< 5, id: \.self) {
                    Text("Number \($0)")
                }
            }
            .onReceive(Just(selection)) {
                print("Selected: \($0)")
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-01 10:02

    Here is what I just decided to use... (deployment target iOS 13)

    struct MyPicker: View {
        @State private var favoriteColor = 0
    
        var body: some View {
            Picker(selection: $favoriteColor.onChange(colorChange), label: Text("Color")) {
                Text("Red").tag(0)
                Text("Green").tag(1)
                Text("Blue").tag(2)
            }
        }
    
        func colorChange(_ tag: Int) {
            print("Color tag: \(tag)")
        }
    }
    

    Using this helper

    extension Binding {
        func onChange(_ handler: @escaping (Value) -> Void) -> Binding<Value> {
            return Binding(
                get: { self.wrappedValue },
                set: { selection in
                    self.wrappedValue = selection
                    handler(selection)
            })
        }
    }
    

    EDIT:

    If your deployment target is set to iOS 14 or higher -- Apple has provided a built in onChange extension to View, which can be used like this instead (Thanks @Jeremy):

    Picker(selection: $favoriteColor, label: Text("Color")) {
        // ..
    }
    .onChange(of: favoriteColor) { print("Color tag: \($0)") }
    
    0 讨论(0)
  • 2020-12-01 10:05

    I know this is a year old post, but I thought this solution might help others that stop by for a visit in need of a solution. Hope it helps someone else.

    import Foundation
    import SwiftUI
    
    struct MeasurementUnitView: View {
        
        @State var selectedIndex = unitTypes.firstIndex(of: UserDefaults.standard.string(forKey: "Unit")!)!
        var userSettings: UserSettings
        
        var body: some View {
            
            VStack {
                Spacer(minLength: 15)
                Form {
                    Section {
                        Picker(selection: self.$selectedIndex, label: Text("Current UnitType")) {
                            
                            ForEach(0..<unitTypes.count, id: \.self) {
                                Text(unitTypes[$0])
                            }
                        }.onReceive([self.selectedIndex].publisher.first()) { (value) in
                            self.savePick()
                        }
                        .navigationBarTitle("Change Unit Type", displayMode: .inline)
                    }
                }
            }
        }
        
        func savePick() {
            
            if (userSettings.unit != unitTypes[selectedIndex]) {
                userSettings.unit = unitTypes[selectedIndex]
            }
        }
    }
    
    
    
    0 讨论(0)
  • 2020-12-01 10:11

    For people that have to support both iOS 13 and 14, I added an extension which works for both. Don't forget to import Combine.

    Extension View {
        @ViewBuilder func onChangeBackwardsCompatible<T: Equatable>(of value: T, perform completion: @escaping (T) -> Void) -> some View {
            if #available(iOS 14.0, *) {
                self.onChange(of: value, perform: completion)
            } else {
                self.onReceive([value].publisher.first()) { (value) in
                    completion(value)
                }
            }
        }
    }
    

    Usage:

    Picker(selection: $selectedIndex, label: Text("Color")) {
        Text("Red").tag(0)
        Text("Blue").tag(1)
    }.onChangeBackwardsCompatible(of: selectedIndex) { (newIndex) in
        print("Do something with \(newIndex)")
    }
    
    0 讨论(0)
提交回复
热议问题