web-dev-qa-db-fra.com

Dérivation de la liaison à partir de SwiftUI @States existants

J'ai joué avec SwiftUI et Combine et j'ai l'impression qu'il y a probablement un moyen d'obtenir les propriétés @State existantes dans une vue et d'en créer une nouvelle.

Par exemple, j'ai une vue de création de mot de passe qui contient un mot de passe et un champ passwordConfirm pour l'utilisateur. Je veux prendre ces deux propriétés @State et dériver un nouveau @State que je peux utiliser dans ma vue qui affirme si l'entrée est valide. Donc pour plus de simplicité: pas vide et égal.

Les Apple docs disent il y a un éditeur sur une liaison, bien que je n'arrive pas à m'en emparer.

Voici un pseudo-code non fonctionnel:

import SwiftUI
import Combine

struct CreatePasswordView : View {
    @State var password = ""
    @State var confirmation = ""
    lazy var valid = {
        return self.$password.publisher()
            .combineLatest(self.$confirmation)
            .map { $0 != "" && $0 == $1 }
    }

    var body: some View {
        SecureField($password, placeholder: Text("password"))

        SecureField($confirmation, placeholder: Text("confirm password"))

        NavigationButton(destination: NextView()) { Text("Done") }
            .disabled(!valid)
    }
}

N'importe qui a trouvé. la manière appropriée de procéder/si c'est possible?

MISE À JOUR Bêta 2:

Depuis la version bêta 2, l'éditeur est disponible, donc la première moitié de ce code fonctionne maintenant. La deuxième moitié de l'utilisation de l'éditeur résultant dans la vue, je ne l'ai toujours pas compris (disabled(!valid)).

import SwiftUI
import Combine

struct CreatePasswordView : View {
    @State var password = ""
    @State var confirmation = ""

    lazy var valid = {
        Publishers.CombineLatest(
            password.publisher(),
            confirmation.publisher(),
            transform: { String($0) != "" && $0 == $1 }
        )
    }()

    var body: some View {
        SecureField($password, placeholder: Text("password"))

        SecureField($confirmation, placeholder: Text("confirm password"))

        NavigationButton(destination: NextView()) { Text("Done") }
            .disabled(!valid)
    }
}

Merci.

9
freebie

Je ne jouerais pas avec @State/@Published as Combine est actuellement en version bêta, mais voici une solution de contournement simple pour ce que vous essayez de réaliser.

Je mettrais en œuvre un modèle de vue pour conserver le mot de passe, la confirmation du mot de passe et s'il est valide ou non

class ViewModel: NSObject, BindableObject {

    var didChange = PassthroughSubject<Void, Never>()

    var password: String = "" {
        didSet {
            didChange.send(())
        }
    }

    var passwordConfirmation: String = "" {
        didSet {
            didChange.send(())
        }
    }

    var isPasswordValid: Bool {
        return password == passwordConfirmation && password != ""
    }

}

De cette façon, la vue est recalculée chaque fois que le mot de passe ou la confirmation change.

Ensuite, je ferais un @ObjectBinding au modèle de vue.

struct CreatePasswordView : View {

    @ObjectBinding var viewModel: ViewModel

    var body: some View {
        NavigationView {
            VStack {
                SecureField($viewModel.password,
                            placeholder: Text("password"))
                SecureField($viewModel.passwordConfirmation,
                            placeholder: Text("confirm password"))
                NavigationButton(destination: EmptyView()) { Text("Done") }
                    .disabled(!viewModel.isPasswordValid)
            }
        }
    }

}

J'ai dû mettre les vues dans un NavigationView, parce que NavigationButton ne semble pas s'activer s'il n'est pas dans l'un d'eux.

3
Matteo Pacini