SwiftUI - folosind variabila conta în ForEach

0

Problema

Am o vedere l-a creat printr-o buclă ForEach care are nevoie pentru a lua o variabilă conta în ForEach sine, adică am nevoie de aplicația pentru a reacționa la o dinamică a număra și de a schimba UI accoridngly.

Aici este punctul de vedere am încercat să modifice:

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)
        }
    }
}

Și viewModel observ:

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)
        }
    }
}

Și în cele din urmă 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
    }
}

Practic, un buton de pe formularul de autentificare se stabilește sale viewModel e isActive proprietate la true. Ne asculta pentru acest lucru în TabBarViewModel și setați activeFormIndex în mod corespunzător. Acest indice este apoi utilizat în buclă ForEach. În esență, în funcție de indicele selectat, am nevoie pentru a genera mai mult sau mai puțin distanțiere în AnimatedTabSelector vedere.

Cu toate acestea, deși activeIndex variabilă este actualizat în mod corect, ForEach nu pare să reacționeze.

Update:

La AnimatedTabSelector este declarat ca făcând parte din această vedere de ansamblu:

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)
        )
    }
}

UPDATE:

Am încercat o altă cale prin adăugarea unui alt publicat la AnimatedTabSelector în sine pentru a verifica faptul că valorile sunt într-adevăr în curs de actualizare în mod corespunzător. Astfel, la sfârșitul HStack din acest punct de vedere, am adăugat:

.onAppear {
            tabBarViewModel.$activeFormIndex.sink { index in
                self.preCircleSpacers = index + 1
                self.postCircleSpacers = tabBarViewModel.loginForms.count - index
            }
            .store(in: &cancellables)
        }

Și, desigur, am adăugat următoarele variabile la acest punct de vedere:

@State var preCircleSpacers = 1
@State var postCircleSpacers = 6
@State var cancellables = Set<AnyCancellable>()

Apoi, în buclele ForEach am schimbat la:

ForEach(1..<preCircleSpacers)

și

ForEach(1..<postCircleSpacers)

respectiv.

Am adăugat un punct de pauză în noua persoana declarația și este într-adevăr a fi la curent cu cele așteptat cifre. Dar punctul de vedere este încă nu reușesc să reflecte schimbările în valorile

combine swift swiftui
2021-11-23 22:03:33
1

Cel mai bun răspuns

0

OK deci se pare că am găsit o soluție - ce presupun este că ForEach conțin o serie nu se actualizează în mod dinamic în același mod în care ForEach care conține o serie de obiecte.

Deci, mai degrabă decât:

ForEach(0..<tabBarViewModel.loginForms.count)

etc.

Am schimbat la:

ForEach(tabBarViewModel.loginForms.prefix(tabBarViewModel.activeFormIndex))

În acest fel eu încă mai repeta de câte ori este necesar, dar ForEach actualizează dinamic cu numărul corect de elemente în matrice

2021-11-23 23:51:48

Se pare că documentația nu spune la fel de mult: "De exemplu, numai citește valoarea inițială a furnizat date și nu are nevoie pentru a identifica opinii pe actualizări. Pentru a calcula vedere la cerere pe o gamă dinamică, folosi ForEach/init(_:id:conținutul:)."
Charles A.

În alte limbi

Această pagină este în alte limbi

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................