微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SwiftUI - 有条件的 onChange

如何解决SwiftUI - 有条件的 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 是否为真。

现在只有在编辑每个 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()
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。