OK, I've figured it out 🙂 I needed two variables, one per TextField: isFocused1, isFocused2. Each of them changes to true with onEditingChanged. And each onChange has if condition that checks if isFocused for this TextField is true.
Now onChange is triggered only if each TextField is being edited. I have added changing background colors to visualize focus changes.
Working code:
import SwiftUI
struct ContentView: View {
@State private var string1: String = ""
@State private var int1: Int = 0
@State private var string2: String = ""
@State private var int2: Int = 0
let multiplier: Int = 2
@State private var isFocused1 = false
@State private var isFocused2 = false
var body: some View {
VStack {
HStack {
TextField("0", text: $string1, onEditingChanged: { (changed) in
isFocused1 = changed
})
.keyboardType(.decimalPad)
.onChange(of: string1, perform: { value in
if isFocused1 {
int1 = Int(string1) ?? 0
int2 = int1 * multiplier
string2 = "\(int2)"
print("int1: \(int1)")
}
})
.background(isFocused1 ? Color.yellow : Color.gray)
}
.multilineTextAlignment(.trailing)
.font(.largeTitle)
HStack {
Spacer()
Text("x2")
}
HStack {
TextField("0", text: $string2, onEditingChanged: { (changed) in
isFocused2 = changed
})
.keyboardType(.decimalPad)
.onChange(of: string2, perform: { value in
if isFocused2 {
int2 = Int(string2) ?? 0
int1 = int2 / multiplier
string1 = ("\(int1)")
print("int2: \(int2)")
}
})
.background(isFocused2 ? Color.yellow : Color.gray)
}
.multilineTextAlignment(.trailing)
.font(.largeTitle)
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}