Home > database >  how to swap two picker value when both of them are same in swiftUI
how to swap two picker value when both of them are same in swiftUI

Time:07-04

in this code I want to change two picker values when they are same to remain this two different from each other. I try to use swap but that's not working properly.

for example : when first picker value is one and second is two, when I try to change second value to "one", value immediately change to one and first picker become two!

 struct ContentView: View {
    @State private var list = ["one","two","three","four","five"]
    @State private var from: String = "one"
    @State private var from: String = "two"
         var body: some View {
       VStack {
          Picker("",selection: $from) {
             ForEach(list, id: \.self) { item in
                Text(item)
         }
       }
       .pickerStyle(.menu)
       .padding(.trailing)
       .onChange(of: from) { newValue in
                                    if newValue == to {
                                        (to,from) = (from, to)
                                    }
                                }  

          Picker("",selection: $to) {
             ForEach(list, id: \.self) { item in
                Text(item)
         }
       }
       .pickerStyle(.menu)
       .padding(.trailing)
    }
    }
}

I'm using this tuple solution for another section of the app but in this part that's not working :

(from, to) = (to, from) 

how can I perform immediately swap this two values when for example to going to the same with from?

CodePudding user response:

I think there is a connection that is missing. You state

If my change in first picker cause two picker become equal, so immediately swap them!

If you swap 2 equal values you get 2 equal values.

Assumption:

What It seems you want is a solution for the standard interview question of swapping 2 values.

Given x=1 and y=2. Swap the values

The way to do this is

let temp = y //holds a value
y = x //starts swap
x = temp //finishes swap

Now your result is y=1 and x=2

You need that temp variable to hold the value of one of them, while you are swapping values.

Now, if we ge back to your statement, the fallacy is in waiting for the values to become equal.

When you click on the new item the change is being made immediately, there is no way to retrieve what the value was previously.

x = newValue or y = newValue

The only way to achieve a "swapping" is to determine if there is a need to swap before the "source of truth" changes.

  1. Pick new value
  2. Check if swapping is needed
  3. Swap the source of truth values
  4. Tell SwiftUI there is an update

You can achieve this setup in SwiftUI with an ObservableObject

class AutoPickerVM: ObservableObject{
    ///Variable that holds the value for From - Source of truth
    private var storeFrom: String = "one"
    ///Processes the changes between the pickers and triggers view updates
    var from: String {
        get{
            storeFrom
        }
        set{
            if newValue == to{
                //Take the value that is currently there
                let curTo = to
                //Start swapping
                storeTo = storeFrom
                //Place the previous value
                storeFrom = curTo
                
            }else{
                storeFrom = newValue
            }
            objectWillChange.send()
        }
    }
    ///Variable that holds the value for to - Source of truth
    private var storeTo: String = "two"
    ///Processes the changes between the pickers and triggers view updates
    var to: String {
        get{
            storeTo
        }
        set{
            if newValue == from{
                //Take the value that is currently there
                let curFrom = from
                //Start swapping
                storeFrom = storeTo
                //Place the previous value
                storeTo = curFrom
            }else{
                storeTo = newValue
            }
            
            objectWillChange.send()
        }
    }
    init(){}
}

Then your View would look like this

struct AutoPicker: View {
    @StateObject var vm: AutoPickerVM = .init()
    @State private var list = ["one","two","three","four","five"]
    
    var body: some View {
        VStack {
            Picker("",selection: $vm.from) {
                ForEach(list, id: \.self) { item in
                    Text(item)
                }
            }
            .pickerStyle(.menu)
            .padding(.trailing)
            
            Picker("",selection: $vm.to) {
                ForEach(list, id: \.self) { item in
                    Text(item)
                }
            }
            .pickerStyle(.menu)
            .padding(.trailing)
        }
    }
}

CodePudding user response:

still not 100% sure what you are trying to do, but it may be something like this, as shown in this example code using helper vars:

struct ContentView: View {
    @State private var list = ["one","two","three","four","five"]
    
    @State private var from: String = "one"
    @State private var to: String = "two"
    
    @State private var prevFrom: String = "one"
    @State private var prevTo: String = "two"
    
    var body: some View {
        VStack {
            Picker("",selection: $from) {
                ForEach(list, id: \.self) { item in
                    Text(item)
                }
            }
            .pickerStyle(.menu)
            .padding(.trailing)
            
            .onChange(of: to) { _ in
                if to == from {
                    from = prevTo
                }
                prevTo = to
            }
            
            .onChange(of: from) { _ in
                if to == from {
                    to = prevFrom
                }
                prevFrom = from
            }
            
            Picker("",selection: $to) {
                ForEach(list, id: \.self) { item in
                    Text(item)
                }
            }
            .pickerStyle(.menu)
            .padding(.trailing)
        }
    }
}
  • Related