【问题标题】:TextField with animation crashes app and looses focus带有动画的 TextField 使应用程序崩溃并失去焦点
【发布时间】:2020-02-23 19:32:46
【问题描述】:

最小的可重现示例:

SceneDelegate.swift:

let contentView = Container()

ContentView.swift:

struct SwiftUIView: View {
    @State var text: String = ""

    var body: some View {
        VStack {
            CustomTextFieldView(text: $text)
        }
    }
}

struct Container: View {

    @State var bool: Bool = false
    @State var text: String = ""

    var body: some View {

        Button(action: {
            self.bool.toggle()
        }) {
            Text("Sheet!")
        }
        .sheet(isPresented: $bool) {
            SwiftUIView()
        }
    }
}

CustomTextField.swift:

struct CustomTextFieldView: View {

    @Binding var text: String
    @State var editing: Bool = false


    var body: some View {
        Group {
            if self.editing {
                textField
                    .background(Color.red)
            } else {
                ZStack(alignment: .leading) {
                    textField
                        .background(Color.green)
                    Text("Placeholder")
                }
            }
        }
        .onTapGesture {
            withAnimation {
                self.editing = true
            }
        }
    }

    var textField: some View {
        TextField("", text: $text)
    }

问题:

运行上述代码并聚焦文本字段后,应用程序崩溃。我注意到的一些事情:

  1. 如果我删除 withAnimation 代码或 CustomTextField 文件中的 ZStack,应用不会崩溃,但 TextField 会失去焦点。
  2. 如果我删除 SwiftUIView 中的 VStack,应用不会崩溃,但 TextField 会失去焦点。
  3. 如果我使用 NavigationLink 或在没有工作表的情况下显示 TextField,应用不会崩溃,但 TextField 会失去焦点。

问题:

  • 这是当前版本的 SwiftUI 的问题吗?
  • 是否有使用 SwiftUI 解决此问题的方法?我想远离 尽可能多地查看可表示对象。
  • 由于状态更改而重新计算正文后,如何保持 TextField 的焦点?

【问题讨论】:

    标签: swift swiftui


    【解决方案1】:
    1. 正文后如何保持 TextField 的焦点 由于状态变化而重新计算?

    你有两个。 两个不同的TextField不能同时处于编辑状态。

    Asperi 建议的方法是唯一可行的方法。

    你的代码崩溃的原因不容易解释,但在当前的 SwiftUI 中是预期的。

    你必须明白,Group 不是一个标准的容器,它就像一个“块”,你可以在上面应用一些修饰符。在 ViewBuilder 中移除 Group 并使用包裹体

    struct CustomTextFieldView: View {
    
        @Binding var text: String
        @State var editing: Bool = false
    
        @ViewBuilder
        var body: some View {
                if self.editing {
                    TextField("", text: $text)
                        .background(Color.red)
                        .onTapGesture {
                            self.editing.toggle()
                    }
                } else {
                    ZStack(alignment: .leading) {
                        TextField("", text: $text)
                            .background(Color.green)
                            .onTapGesture {
                                    self.editing.toggle()
                            }
                    }
            }
    
        }
    }
    

    代码将停止崩溃,但还有其他问题,键盘将立即关闭。这是由于应用了轻击手势。

    所以,不管你信不信,你只能使用一个 TextField。

    struct CustomTextFieldView: View {
    
        @Binding var text: String
        @State var editing = false
    
        var textField: some View {
            TextField("", text: $text, onEditingChanged: { edit in
                self.editing = edit
            })
        }
    
        var body: some View {
    
            textField.background(editing ? Color.green : Color.red)
    
        }
    }
    

    根据需要在代码的其他地方使用此自定义文本字段

    【讨论】:

    • 我的原始代码中没有 2 个不同的 TextField。我会更新我的问题。
    • 那是你的错误,实际上是你的代码中两个分开的 TextFields
    • 好吧,那么问题是:是否有一个 TextField 方法可以以编程方式聚焦 TextField?答案是否定的。所以我想我将不得不使用 ViewRepresentables。无论如何,崩溃仍然存在。
    • @CarlesMitjans 有充分的理由,禁止强制用户编辑字段。用户必须决定要编辑哪个字段以及何时编辑。如果您愿意,可以根据需要禁用字段编辑。请参阅 .disabled(bool) 修饰符。
    • @CarlesMitjans 在这里查看其他解决方案stackoverflow.com/questions/60379010/… 但要小心,它可能会在下一个版本中停止工作(它使用未记录的 TextFieldStyle)
    【解决方案2】:

    CustomTextFieldView 尝试以下操作(测试并适用于 Xcode 11.2 / iOS 13.2)

    struct CustomTextFieldView: View {
    
        @Binding var text: String
        @State var editing: Bool = false
    
    
        var body: some View {
            TextField("", text: $text)
                .background(self.editing ? Color.red : Color.green)
                .onTapGesture {
                    withAnimation {
                        self.editing = true
                    }
                }
        }
    }
    

    由于状态改变而重新计算body后如何保持TextField的焦点?

    你没有失去焦点,你只是删除了整个文本字段,所以解决方案不是替换文本字段,而是修改它的属性,即背景。放到 ZStack 里面没问题,但要留一个。

    【讨论】:

    • 谢谢,它有效。但问题是我必须使用带有 if 块的 ZStack。我将编辑捕获此问题的问题。
    • withAnimation 有什么用?
    猜你喜欢
    • 1970-01-01
    • 2020-05-27
    • 1970-01-01
    • 2011-08-05
    • 1970-01-01
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多