问题描述
我有 2 个文本字段: __ x2 __
我想执行简单的计算:string1 x 2 = string2。我正在使用 .onChange 修饰符,因此如果您输入第一个数字,它将乘以 2,结果将打印在第二个 TextField 中。您可以反过来输入 string2,它将除以 2,结果将打印在第一个 TextField 中。
现在因为两个 TextField 都有 .onChange,它会被触发几次(在这种情况下为 3)。更改 string1 后,string2 会更新。随着它的变化,string2 的 .onChange 被触发,随后与 string1 的 .onChange 相同。
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
var body: some View {
vstack {
HStack {
TextField("0",text: $string1)
.keyboardType(.decimalPad)
.onChange(of: string1,perform: { value in
string1 = value
int1 = Int(string1) ?? 0
int2 = int1 * multiplier
string2 = "\(int2)"
print("int1: \(int1)")
})
}
.multilineTextAlignment(.trailing)
.font(.largeTitle)
.background(Color(UIColor.systemGray5))
HStack {
Spacer()
Text("x2")
}
HStack {
TextField("0",text: $string2)
.keyboardType(.decimalPad)
.onChange(of: string2,perform: { value in
string2 = value
int2 = Int(string2) ?? 0
int1 = int2 / multiplier
string1 = ("\(int1)")
print("int2: \(int2)")
})
}
.multilineTextAlignment(.trailing)
.font(.largeTitle)
.background(Color(UIColor.systemGray5))
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
问题:
如何使 .onChange 有条件,使其只运行一次?准确地说,我只想在编辑第一个输入时对第一个输入执行 .onChange 。并仅在我编辑第二个输入时对第二个输入执行 .onChange。
在 iOS 15 中使用 .onFocus 可能会很容易。但是如何在 iOS 14 中做到这一点?
解决方法
我已经想通了。我需要两个变量,每个 TextField 一个:isFocused1、isFocused2。它们中的每一个都通过 onEditingChanged 更改为 true。并且每个 onChange 都有 if 条件来检查此 TextField 的 isFocused 是否为真。
现在只有在编辑每个 TextField 时才会触发 onChange。我添加了不断变化的背景颜色以可视化焦点变化。
工作代码:
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()
}
}
根据@JoakimDanielson 的反馈,我制作了一个带有枚举而不是 2 个单独变量的版本:
import SwiftUI
struct ContentView: View {
enum Focus {
case input1
case input2
}
@State private var isFocused: Focus?
@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
var body: some View {
VStack {
HStack {
TextField("0",onEditingChanged: { (changed) in
if changed {
isFocused = Focus.input1
}
})
.keyboardType(.decimalPad)
.onChange(of: string1,perform: { value in
if isFocused == .input1 {
int1 = Int(string1) ?? 0
int2 = int1 * multiplier
string2 = "\(int2)"
print("int1: \(int1)")
}
})
.background(isFocused == .input1 ? Color.yellow : Color.gray)
}
.multilineTextAlignment(.trailing)
.font(.largeTitle)
HStack {
Spacer()
Text("x2")
}
HStack {
TextField("0",onEditingChanged: { (changed) in
if changed {
isFocused = Focus.input2
}
})
.keyboardType(.decimalPad)
.onChange(of: string2,perform: { value in
if isFocused == .input2 {
int2 = Int(string2) ?? 0
int1 = int2 / multiplier
string1 = ("\(int1)")
print("int2: \(int2)")
}
})
.background(isFocused == .input2 ? Color.yellow : Color.gray)
}
.multilineTextAlignment(.trailing)
.font(.largeTitle)
}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}