SwiftUİ-ForEach içinde değişken sayımı kullanma

0

Soru

Foreach'in içinde değişken bir sayım yapması gereken bir ForEach döngüsü aracılığıyla oluşturulmuş bir görünümüm var, yani uygulamanın dinamik bir sayıma tepki vermesi ve kullanıcı arayüzünü uyumlu bir şekilde değiştirmesi gerekiyor.

İşte değiştirmeye çalıştığım görünüm:

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

Ve gözlemlediğim viewModel:

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

Ve son olarak 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
    }
}

Temel olarak, oturum açma formundaki bir düğme, Viewmodel'in isActive özelliğini true olarak ayarlar. Bunu Tabbarviewmodel'de dinliyoruz ve activeformındex'i buna göre ayarlıyoruz. Bu dizin daha sonra ForEach döngüsünde kullanılır. Esasen, seçilen dizine bağlı olarak, AnimatedTabSelector görünümünde daha fazla veya daha az aralayıcı oluşturmam gerekiyor.

Ancak, activeIndex değişkeni doğru güncelleştirilirken, ForEach yanıt vermiyor gibi görünüyor.

Güncelleme:

AnimatedTabSelector bu genel görünümün bir parçası olarak bildirilir:

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

Güncelleme:

Değerlerin gerçekten buna göre güncellendiğini kontrol etmek için animatedtabselector'a yayınlanmış başka bir yol ekleyerek başka bir yol denedim. Bu yüzden bu görünümdeki Hstack'in sonunda ekledim:

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

Ve elbette bu görünüme aşağıdaki değişkenleri ekledim:

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

Sonra ForEach döngülerinde değiştirdim:

ForEach(1..<preCircleSpacers)

ve

ForEach(1..<postCircleSpacers)

sırasıyla.

Yeni yayıncı bildirimine bir kesme noktası ekledim ve gerçekten beklenen rakamlarla güncelleniyor. Ancak görünüm hala değerlerdeki değişimi yansıtmıyor

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

En iyi cevabı

0

Tamam, bu yüzden bir çözüm buldum gibi görünüyor-varsaydığım şey, bir aralık içeren Foreach'in, bir dizi nesne içeren Foreach'in yaptığı gibi dinamik olarak güncellenmemesidir.

Yani yerine:

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

vb.

Değiştirdim :

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

Bu şekilde hala gerekli sayıda yinelemeyi yapıyorum, ancak ForEach dizideki doğru sayıda öğeyle dinamik olarak güncelleniyor

2021-11-23 23:51:48

Görünüşe göre belgeleri yok demek kadar: "örnek sadece okur başlangıç değer verilen veri ve gerekmez tanımlamak için görünümler arasında günceller. Dinamik aralık üzerinden isteğe bağlı görünümleri hesaplamak için ForEach/init(_:id:content:) kullanın."
Charles A.

Diğer dillerde

Bu sayfa diğer dillerde

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