J'ai une vue créée par une boucle ForEach qui doit prendre une variable de comptage dans le ForEach lui-même c'est à dire j'ai besoin de l'application pour réagir à une dynamique de comptage et de modifier l'INTERFACE utilisateur accoridngly.
Voici la vue que je suis en train de la modifier:
struct AnimatedTabSelector: View {
let buttonDimensions: CGFloat
@ObservedObject var tabBarViewModel: TabBarViewModel
var body: some View {
HStack {
Spacer().frame(maxWidth: .infinity).frame(height: 20)
.background(Color.red)
ForEach(1..<tabBarViewModel.activeFormIndex + 1) { _ in
Spacer().frame(maxWidth: buttonDimensions).frame(height: 20)
.background(Color.blue)
Spacer().frame(maxWidth: .infinity).frame(height: 20)
.background(Color.green)
}
Circle().frame(
width: buttonDimensions,
height: buttonDimensions)
.foregroundColor(
tabBarViewModel.activeForm.loginFormViewModel.colorScheme
)
ForEach(1..<tabBarViewModel.loginForms.count - tabBarViewModel.activeFormIndex) { _ in
Spacer().frame(maxWidth: .infinity).frame(height: 20)
.background(Color.red)
Spacer().frame(maxWidth: buttonDimensions).frame(height: 20)
.background(Color.blue)
}
Spacer().frame(maxWidth: .infinity).frame(height: 20)
.background(Color.gray)
}
}
}
Et le dernier que j'observe:
class TabBarViewModel: ObservableObject, TabBarCompatible {
var loginForms: [LoginForm]
@Published var activeForm: LoginForm
@Published var activeFormIndex = 0
private var cancellables = Set<AnyCancellable>()
init(loginForms: [LoginForm]) {
self.loginForms = loginForms
self.activeForm = loginForms[0] /// First form is always active to begin
setUpPublisher()
}
func setUpPublisher() {
for i in 0..<loginForms.count {
loginForms[i].loginFormViewModel.$isActive.sink { isActive in
if isActive {
self.activeForm = self.loginForms[i]
self.activeFormIndex = i
}
}
.store(in: &cancellables)
}
}
}
Et enfin le loginFormViewModel:
class LoginFormViewModel: ObservableObject {
@Published var isActive: Bool
let name: String
let icon: Image
let colorScheme: Color
init(isActive: Bool = false, name: String, icon: Image, colorScheme: Color) {
self.isActive = isActive
self.name = name
self.icon = icon
self.colorScheme = colorScheme
}
}
En fait, un bouton sur le formulaire de connexion en elle-même définit son viewModel de l'est actif true à la propriété. Nous écoutent ce dans TabBarViewModel et définir la activeFormIndex en conséquence. Cet indice est ensuite utilisé dans la boucle ForEach. Essentiellement, en fonction de l'indice choisi, j'ai besoin de générer plus ou moins les entretoises dans le AnimatedTabSelector vue.
Cependant, alors que la activeIndex variable est correctement mis à jour, le ForEach ne semble pas réagir.
Mise à jour:
Le AnimatedTabSelector est déclaré dans le cadre de cette vue d'ensemble:
struct TabIconsView: View {
struct Constants {
static let buttonDimensions: CGFloat = 50
static let buttonIconSize: CGFloat = 25
static let activeButtonColot = Color.white
static let disabledButtonColor = Color.init(white: 0.8)
struct Animation {
static let stiffness: CGFloat = 330
static let damping: CGFloat = 22
static let velocity: CGFloat = 7
}
}
@ObservedObject var tabBarViewModel: TabBarViewModel
var body: some View {
ZStack {
AnimatedTabSelector(
buttonDimensions: Constants.buttonDimensions,
tabBarViewModel: tabBarViewModel)
HStack {
Spacer()
ForEach(tabBarViewModel.loginForms) { loginForm in
Button(action: {
loginForm.loginFormViewModel.isActive = true
}) {
loginForm.loginFormViewModel.icon
.font(.system(size: Constants.buttonIconSize))
.foregroundColor(
tabBarViewModel.activeForm.id == loginForm.id ? Constants.activeButtonColot : Constants.disabledButtonColor
)
}
.frame(width: Constants.buttonDimensions, height: Constants.buttonDimensions)
Spacer()
}
}
}
.animation(Animation.interpolatingSpring(
stiffness: Constants.Animation.stiffness,
damping: Constants.Animation.damping,
initialVelocity: Constants.Animation.velocity)
)
}
}
Mise à JOUR:
J'ai essayé une autre manière, en ajoutant un autre publié le AnimatedTabSelector elle-même de vérifier que les valeurs sont en effet d'être mis à jour en conséquence. Ainsi, à la fin de la HStack dans cette vue, j'ai ajouté:
.onAppear {
tabBarViewModel.$activeFormIndex.sink { index in
self.preCircleSpacers = index + 1
self.postCircleSpacers = tabBarViewModel.loginForms.count - index
}
.store(in: &cancellables)
}
Et bien sûr, j'ai ajouté les variables suivantes de ce point de vue:
@State var preCircleSpacers = 1
@State var postCircleSpacers = 6
@State var cancellables = Set<AnyCancellable>()
Puis, dans les boucles ForEach j'ai changé pour:
ForEach(1..<preCircleSpacers)
et
ForEach(1..<postCircleSpacers)
respectivement.
J'ai ajouté un point d'arrêt dans l'éditeur de déclaration et de il est en effet d'être mis à jour avec les chiffres. Mais la vue est toujours pas refléter les changements dans les valeurs