I want to understand if I got this concept correctly.
- I should start work from
ViewState
; a reference type object holding the state of a view. Here it is calledPageIndicatorVM
. It is bad-to-impossible to have any internal state in aView
. - No logic in the
View
or so they say. Yet here and there in the code samples I see ternary operators and loops. @Bidindg
property wrapper seems quite dangerous for me. It breaks unidirectional data flow and I have doubts if I used it correctly here.
Please point out my mistakes. Will appreciate if you point me to best practices.
This is a dot indicator component. It switches when vm.next()
is called or user taps on a dot.
struct DotIndicator: View { let pageIndex: Int @Binding var isOn: Int var body: some View { Button(action: { self.isOn = self.pageIndex }) { Circle() .scaleEffect( isOn == pageIndex ? 1.3 : 0.9) .animation(.spring()) } } } class PageIndicatorVM: ObservableObject { @Published var currentPage: Int let numPages: Int init(numPages: Int, currentPage: Int = 0) { self.numPages = numPages self.currentPage = currentPage } func next() { currentPage = (currentPage + 1) % numPages } } struct PageIndicator: View { @ObservedObject private var vm = PageIndicatorVM(numPages: 5) private let spacing: CGFloat = 2 private let dotSize: CGFloat = 8 var body: some View { VStack { HStack(alignment: .center, spacing: spacing) { ForEach((0..<vm.numPages ), id: \.self) { DotIndicator(pageIndex: $0, isOn: self.$vm.currentPage) .frame( width: self.dotSize, height: self.dotSize ) } } } } }