繁体   English   中英

SwiftUI 焦点 State API 环境变量不工作

[英]SwiftUI Focus State API environment variable not working

当我们想要观察 SwiftUI 文本字段的焦点 state 时,环境值 isFocused 似乎不起作用。 除了将值传递给 TextFieldStyle 的初始化(我们必须为每个文本字段执行此操作)之外,还有其他方法可以做到这一点吗? 也不适用于设备。

当其焦点 state 发生变化时,更改 Textfield 外观的首选方法是什么?

例子:

SwiftUI TextFieldStyle定义如下:

struct MyTextFieldStyle: TextFieldStyle {
    @Environment(\.isFocused) var isFocused: Bool

    func _body(configuration: TextField<_Label>) -> some View {
        configuration
            .padding()
            .overlay(
                RoundedRectangle(
                    cornerRadius: 10.0, style: .continuous
                )
                .stroke(isFocused ? .green : .gray, lineWidth: 3)
            )
            .accentColor(Color(uiColor: .white))
    }
}

#if DEBUG
private struct TestView: View {
    @FocusState private var focusedTextfield: FocusField?

    enum FocusField: Hashable {
        case textfield1, textfield2
    }

    var body: some View {
        VStack(spacing: 16) {
            TextField("hello", text: .constant("Hi"))
                .textFieldStyle(MyTextFieldStyle())
                .focused($focusedTextfield, equals: .textfield1)

            TextField("hello", text: .constant("Hi"))
                .textFieldStyle(MyTextFieldStyle())
                .focused($focusedTextfield, equals: .textfield2)
        }.onAppear {
            focusedTextfield = .textfield1
        }
    }
}

struct MyTextfieldStyle_Previews: PreviewProvider {
    static var previews: some View {
        ZStack {
            TestView()
        }
    }
}
#endif

// 编辑:工作解决方案基于https://stackoverflow.com/a/72092987/7828383

struct MyTextFieldStyle: TextFieldStyle {
    @FocusState var isFocused: Bool

    func _body(configuration: TextField<_Label>) -> some View {
        configuration
            .padding()
            .focused($isFocused)
            .overlay(
                RoundedRectangle(
                    cornerRadius: 10.0, style: .continuous
                )
                .stroke(isFocused ? .green : .gray, lineWidth: 3)
            )
            .accentColor(Color(uiColor: .white))
    }
}

#if DEBUG
private struct TestView: View {
    @FocusState private var focusedTextfield: FocusField?

    enum FocusField: Hashable {
        case textfield1, textfield2
    }

    var body: some View {
        VStack(spacing: 16) {
            TextField("hello", text: .constant("Hi"))
                .textFieldStyle(MyTextFieldStyle())
                .focused($focusedTextfield, equals: .textfield1)

            TextField("hello", text: .constant("Hi"))
                .textFieldStyle(MyTextFieldStyle())
                .focused($focusedTextfield, equals: .textfield2)
        }.onAppear {
            DispatchQueue.main.async {
                focusedTextfield = .textfield1
            }
        }
    }
}

struct MyTextFieldStyle_Previews: PreviewProvider {
    static var previews: some View {
        ZStack {
            TestView()
        }
    }
}
#endif

您遇到了几个不同的问题:

  1. 据我所知,自定义 TextFieldStyles 没有公共协议。 但是您可以使用相同的行为来创建自己的 TextField 结构。
  2. 在此结构中,您可以使用另一个本地@FocusState var。 我没有让环境 var 工作,但这确实如此。
  3. 要在主视图中设置初始焦点,您必须使用asyncAfter等待一段时间
struct MyTextField: View {

    @FocusState private var isFocused: Bool

    let title: String
    @Binding var text: String
    
    init(_ title: String, text: Binding<String>) {
        self.title = title
        self._text = text
    }
    
    var body: some View {
        TextField(title, text: $text)
            .focused($isFocused) // important !
            .padding()
            .overlay(
                RoundedRectangle(
                    cornerRadius: 10.0, style: .continuous
                )
                .stroke(isFocused ? .green : .gray, lineWidth: 3)
            )
            .accentColor(Color(uiColor: .red))
    }
}


struct ContentView: View {
    
    @FocusState private var focusedTextfield: FocusField?
    
    enum FocusField: Hashable {
        case textfield1, textfield2
    }
    
    @State private var input1 = "Hi"
    @State private var input2 = "Hi2"

    var body: some View {
        VStack(spacing: 16) {
            MyTextField("hello", text: $input1)
                .focused($focusedTextfield, equals: .textfield1)
            
            MyTextField("hello", text: $input2)
                .focused($focusedTextfield, equals: .textfield2)
            
            // test for changing focus
            Button("Field 1") { focusedTextfield = .textfield1}
            Button("Field 2") { focusedTextfield = .textfield2}

        }
        .padding()
        .onAppear {
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                focusedTextfield = .textfield1
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM