Как привязать функцию в модели представления к пользовательскому представлению в swiftui?

#swiftui

#swiftui

Вопрос:

У меня есть пользовательское текстовое поле:

 struct InputField: View {

    var inputText: Binding<String>
    var title: String
    var placeholder: String
    @State var hasError = false

    var body: some View {
        VStack(spacing: 5.0) {
            HStack {
                Text(title)
                    .font(.subheadline)
                    .fontWeight(.semibold)
                Spacer()
            }
            TextField(placeholder, text: inputText).frame(height: 50).background(Color.white)
                .cornerRadius(5.0)
                .border(hasError ? Color.red : Color.clear, width: 1)

        }
    }
}
 

моя модель представления:

 class LoginViewModel: ObservableObject {
 
    @Published var username = "" {
        didSet {
            print("username is: (username)")
        }
    }
     func checkUsernameisValid() -> Bool {
        return username.count < 6
    }
}
 

и мой окончательный вид входа в систему:

 @ObservedObject var loginViewModel = LoginViewModel()

var inputFields: some View {
        VStack {
            InputField(inputText: $loginViewModel.username, title: "Username:", placeholder: "  Enter your username", hasError: $loginViewModel.checkUsernameisValid())
            InputField(inputText: $loginViewModel.password, title: "Password:", placeholder: "  Enter your password", hasError: $loginViewModel.checkUsernameisValid())
        }
  }
 

Теперь это жалуется на hasError:$loginViewModel.checkUsernameisValid() то, что я не могу привязать функцию к переменной состояния hasError .

Как я могу заставить это работать, продолжая использовать функцию checkUsernameisValid() для обновления моего пользовательского представления текстового поля?

Один из способов решить эту проблему — использовать другую опубликованную переменную в моей модели представления

 @Published var validUsername = false

 func checkUsernameisValid() {
    validUsername = username.count < 6
}
 

и продолжайте вызывать эту функцию в didSet моего имени пользователя var

 @Published var username = "" {
    didSet {
        print("username is: (username)")
        checkUsernameisValid()
    }
}
 

наконец, используйте новую опубликованную переменную для привязки ошибки:

 hasError: $loginViewModel.validUsername
 

Мой вопрос в том, это единственный способ? т.е. Использовать @published var для привязки, и я не могу использовать автономные функции напрямую, чтобы делать то же самое, вместо того, чтобы использовать все больше и больше переменных @Published ?

Ответ №1:

Вам не нужна привязка для ошибки. InputField Будет обновляться inputText , поэтому вам просто нужно обычное свойство, например

 struct InputField: View {

    var inputText: Binding<String>
    var title: String
    var placeholder: String
    var hasError = false       // << here !!

// ...
}
 

а теперь передайте просто вызов

 InputField(inputText: $loginViewModel.username, title: "Username:", placeholder: "  Enter your username", 
     hasError: loginViewModel.checkUsernameisValid())   // << here !!
 

Протестировано с Xcode 12.1 / iOS 14.1

ДЕМОНСТРАЦИЯ

Ответ №2:

Попробуйте:

 @ObservedObject var loginViewModel = LoginViewModel()

var inputFields: some View {
        VStack {
            InputField(inputText: $loginViewModel.username, title: "Username:", placeholder: "  Enter your username", hasError: loginViewModel.checkUsernameisValid())
            InputField(inputText: $loginViewModel.password, title: "Password:", placeholder: "  Enter your password", hasError: loginViewModel.checkUsernameisValid())
        }
  }
 

Функция работает с фактическим значением связанной переменной, а не с самой привязкой.