@FocusState and @AppStorage in SwiftUI (二)

72 阅读2分钟

接着上节留下的问题,我们继续来改造。
在开始之前,我们再来看看问题

问题:
如果我的输入框不止这四个,如果是一个简历输入页面,将有很多信息要录入,那么如果一个页面的TextField有10个该怎么办?还是使用上述方法吗?

其实,SwiftUI提供了一种更加方便的方法来做这种多个TextField的任务

public func focused<Value>(
_ binding: FocusState<Value>.Binding, 
equals value: Value
) -> some View where Value : Hashable

第一个参数:需要一个FocusState.Binding 类型的绑定值

第二个参数:需要输入的值是遵循Hashable协议的

那么我们就来改造,我们把之前的所有使用@FocusState修饰的属性全部变成枚举值,让这个枚举遵循Hashable协议。

private enum OnboardingField: Hashable {
        case name
        case password
        case againPassword
        case email
}

其次,把绑定的方法变了

由 .focused(focusState) 变成 .focused($fieldInFocus, equals: focusField)

// .focused(focusState)
.focused($fieldInFocus, equals: focusField)

最后我们需要把submit的方法也改了

private func submit() {
        if fieldInFocus == .name {
            fieldInFocus = .password
        } else if fieldInFocus == .password {
            fieldInFocus = .againPassword
        } else if fieldInFocus == .againPassword {
            fieldInFocus = .email
        } else {
            print("Done")
        }
    }

这样就可以实现多个TextField的任务了,如果你有多个TextField,那么你继续扩展枚举值就可以来实现任务的增加。

以下是全部代码:

struct FocusStateSample: View {
    
    let textFieldBackgroundColor = #colorLiteral(red: 0.9496834874, green: 0.9635508657, blue: 1, alpha: 1)
    
    // State
    @State private var name: String = ""
    @State private var password: String = ""
    @State private var againPassword: String = ""
    @State private var email: String = ""
    
    private enum OnboardingField: Hashable {
        case name
        case password
        case againPassword
        case email
    }
    
    //    @FocusState var nameFocused: Bool
    //    @FocusState var passwordFocused: Bool
    //    @FocusState var againPasswordFocused: Bool
    //    @FocusState var emailFocused: Bool
    
    // Storage
    @AppStorage("name") var currentName: String?
    @AppStorage("pwd") var currentPassword: String?
    @AppStorage("againpwd") var currentAgainPassword: String?
    @AppStorage("email") var currentEmail: String?
    
    @FocusState private var fieldInFocus: OnboardingField?
    
    var body: some View {
        NavigationView {
            ScrollView {
                VStack(spacing: 20) {
                    markTextField("Input your name", bindingName: $name, submitLabel: .next, keyboardTypeL: .default, focusField: .name)
                    markTextField("Input your password", bindingName: $password, submitLabel: .next, keyboardTypeL: .default, focusField: .password)
                    markTextField("Input your password again", bindingName: $againPassword, submitLabel: .next, keyboardTypeL: .default, focusField: .againPassword)
                    markTextField("Input your email", bindingName: $email, submitLabel: .done, keyboardTypeL: .emailAddress, focusField: .email)
                    Button {
                        save()
                    } label: {
                        Text("Save".uppercased())
                            .foregroundColor(.white)
                            .font(.headline)
                            .fontWeight(.semibold)
                            .frame(height: 55)
                            .frame(maxWidth: .infinity)
                            .background(Color.blue.cornerRadius(10))
                    }
                    Spacer()
                }
            }
            .padding()
            .navigationTitle("Focus state")
            .onTapGesture {
                dismissKeyboard()
            }
            .onAppear {
                autoFillContent()
                guard name.count == 0 else { return }
                
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
                    fieldInFocus = .name
                })
            }
        }
    }
    
    private func markTextField(
        _ prompt: String,
        bindingName: Binding<String>,
        submitLabel: SubmitLabel,
        keyboardTypeL: UIKeyboardType,
        focusField: OnboardingField
    ) -> some View {
        TextField(prompt, text: bindingName)
            .font(.headline)
            .frame(height: 55)
        //            .focused(focusState)
            .focused($fieldInFocus, equals: focusField)
            .submitLabel(submitLabel)
            .keyboardType(keyboardTypeL)
            .padding(.horizontal)
            .background(Color(uiColor: textFieldBackgroundColor))
            .cornerRadius(10)
            .onSubmit {
                submit()
            }
    }
    
    //    private func markTextField(
    //        _ prompt: String,
    //        bindingName: Binding<String>,
    //        submitLabel: SubmitLabel,
    //        keyboardTypeL: UIKeyboardType,
    //        focusState: FocusState<Bool>.Binding
    //    ) -> some View {
    //        TextField(prompt, text: bindingName)
    //            .font(.headline)
    //            .frame(height: 55)
    //            .focused(focusState)
    //            .submitLabel(submitLabel)
    //            .keyboardType(keyboardTypeL)
    //            .padding(.horizontal)
    //            .background(Color(uiColor: textFieldBackgroundColor))
    //            .cornerRadius(10)
    //            .onSubmit {
    //                submit()
    //            }
    //    }
    
    // Hide keyboard, When you tap blank space
    func dismissKeyboard(){
        UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
    
    // MARK: FUNCTIONS
    
    private func submit() {
        if fieldInFocus == .name {
            fieldInFocus = .password
        } else if fieldInFocus == .password {
            fieldInFocus = .againPassword
        } else if fieldInFocus == .againPassword {
            fieldInFocus = .email
        } else {
            print("Done")
        }
    }
    
    //    private func submit() {
    //        if nameFocused {
    //            nameFocused = false
    //            passwordFocused = true
    //        } else if passwordFocused {
    //            passwordFocused = false
    //            againPasswordFocused = true
    //        } else if againPasswordFocused {
    //            againPasswordFocused = false
    //            emailFocused = true
    //        } else {
    //            print("Done")
    //        }
    //    }
    
    private func save() {
        currentName = name
        currentPassword = password
        currentAgainPassword = againPassword
        currentEmail = email
        
        print("Saved")
    }
    
    private func autoFillContent() {
        name = currentName ?? ""
        password = currentPassword ?? ""
        againPassword = currentAgainPassword ?? ""
        email = currentEmail ?? ""
    }
}

struct FocusStateSample_Previews: PreviewProvider {
    static var previews: some View {
        FocusStateSample()
    }
}

大家有什么看法呢?欢迎留言讨论。
公众号:RobotPBQ