点击条件部分中的文本字段时应用程序冻结

App freeze when tap on textfield in conditional section

我有一个可以通过编程方式修改的文本字段。 它工作正常,直到有条件地显示表单部分,在这种情况下,当我使用文本字段时应用程序会冻结。

这是我的代码(我删除了不必要的东西):

struct test: View {
    @Environment(\.presentationMode) var presentationMode
    @State private var displaySection = true
    @State private var amount: Double?
    @FocusState private var isFocused: Bool
    
    var body: some View {
        NavigationView{
            Form {
                if displaySection {     // <-- works well without that condition, otherwise app freezes
                    Section {
                        VStack {
                            HStack {
                                Text("Amount EUR")
                                Spacer()
                                TextField("Type amount", value: $amount, format: .number)
                                    .keyboardType(.numberPad)
                                    .multilineTextAlignment(.trailing)
                                    .focused($isFocused)
                            }
                            Text("Set MAX (999)")
                                .frame(maxWidth: .infinity, alignment: .leading)
                                .onTapGesture {
                                    isFocused = false
                                    amount = 999
                                }
                        }
                    }
                }
            }
        }
    }
}

我需要在表单中隐藏一些部分,所以我一直坚持下去,没有成功回避这个问题。问题出现在模拟器和设备上。

这种行为是否正常,或者是否有可能的解决方法? 感谢您的帮助:)

分而治之。

你在你的应用程序中出现了一个非常奇怪的行为,我永远无法想象这样的错误。我测试了你的代码,它实际上冻结了应用程序。

现在,我测试了以下解决方案:将您的 Section 移至单独的视图。在我的 Xcode 中,它有效。

struct Example: View {
    @Environment(\.presentationMode) var presentationMode
    @State private var displaySection = true
    
    var body: some View {
        NavigationView{
            Form {
                if displaySection {     // <-- works well ALSO WITH that condition
                    ConditionalSection()
                }
                
                Button {
                    withAnimation {
                        displaySection.toggle()
                    }
                } label: {
                    Text("Display or not display?")
                }
            }
        }
    }
}

struct ConditionalSection: View {
    @State private var amount: Double?
    @FocusState private var isFocused: Bool
    
    var body: some View {
        Section {
            VStack {
                HStack {
                    Text("Amount EUR")
                    Spacer()
                    TextField("Type amount", value: $amount, format: .number)
                        .keyboardType(.numberPad)
                        .multilineTextAlignment(.trailing)
                        .focused($isFocused)
                }
                Text("Set MAX (999)")
                    .frame(maxWidth: .infinity, alignment: .leading)
                    .onTapGesture {
                        isFocused = false
                        amount = 999
                    }
            }
        }

    }
}

所以在 Intel 上使用 Xcode 13.2.1 和 iOS 15.2 如果我输入一个数字,我只能在模拟器和真实设备上将此示例代码设为 lock-up 'Amount EUR' 中超过三位数,然后尝试 'Set the Max to 999' 即三位数。

在以前的 SwiftUI 版本中,TextField 唯一可以使用的输入绑定是 String。似乎尽管当前版本接受绑定到数字,但它这样做的方式是映射,并且底层机制仍然是基于原始字符串的 TextField 的机制(不幸的是,在带有附加键盘的 TextField 中键入仍然呈现 non-numeric 字符,不管键盘类型如何,就像我上次试验时那样 https://gist.github.com/shufflingB/23daafa5253c3355cdf18934599cd54c)

无论出于何种原因,当输入的数字超过三位时,这个新的(大概)映射过程似乎会变得混乱,然后 TextField 默认会自动添加数字分组字符。

两个 work-arounds 似乎解决了问题:

  1. 使用 DispatchQueue.main.asyncAfter

    将由 Set the Max ... 触发的 amount 的更改推送到稍后的状态更新周期
  2. 提供一个选项以从 TextField 中删除麻烦的分组字符。

struct ContentView: View {
    @Environment(\.presentationMode) var presentationMode
    @State private var displaySection = true
    @State private var amount: Double?
    @FocusState private var isFocused: Bool

    var body: some View {
        NavigationView {
            Form {
                if displaySection {
                    Section {
                        VStack {
                            HStack {
                                Text("Amount EUR")
                                Spacer()
                                TextField("Type amount", value: $amount, format: .number)
                                    .keyboardType(.numberPad)
                                    .multilineTextAlignment(.trailing)
                                    .focused($isFocused)

                                /* Alternative to Dispatch, remove number grouping
                                TextField("Type amount", value: $amount, format: .number.grouping(.never))
                                    .keyboardType(.numberPad)
                                    .multilineTextAlignment(.trailing)
                                    .focused($isFocused)
                                 */
                            }
                            Text("Set MAX (999)")
                                .frame(maxWidth: .infinity, alignment: .leading)
                                .onTapGesture {
                                    isFocused = false
                                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { // <- Push change to subsequent update cycle
                                        amount = 999
                                    }
                                }
                        }
                    }
                }
            }
        }
    }
}