SwiftUI - 条件 onChange
SwiftUI - conditional onChange
我有 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 是否为真。
现在onChange只有在编辑每个TextField时才会触发。我添加了不断变化的背景颜色以可视化焦点变化。
工作代码:
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", text: $string1, 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", text: $string2, 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()
}
}
我有 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 是否为真。
现在onChange只有在编辑每个TextField时才会触发。我添加了不断变化的背景颜色以可视化焦点变化。
工作代码:
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", text: $string1, 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", text: $string2, 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()
}
}