I'm trying to create a custom dot indicator view. This is the code so far. But the problem is, when I tried this in the preview, the "activeIndex" state didn't change and the indicator didn't show as expected. It still stuck at index 0. Can anybody help? Thanks.
Here's the code:
import SwiftUI
public struct CustomDotIndicatorView: View {
let indicatorCount: Int
@Binding var activeIndex: Int
let height: CGFloat
let spacing: CGFloat
public var body: some View {
let actualActiveIndex = min(max(activeIndex, 0), indicatorCount - 1)
return HStack(alignment: .center, spacing: spacing) {
ForEach(0..<indicatorCount) { index in
CloveDotItemView(
isActive: Binding(get: { actualActiveIndex == index },
set: { _ in }))
}
}
.frame(height: height)
}
}
private struct CustomDotItemView: View {
@Binding var isActive: Bool
private let activeImage: some View = Image( "dotindicator-active", bundle: Bundle(identifier: bundleID))
.renderingMode(.original)
.colorMultiply(.green)
private let inactiveImage: some View = Image( "dotindicator-inactive", bundle: Bundle(identifier: bundleID))
var body: some View {
ZStack {
if isActive {
self.activeImage
} else {
self.inactiveImage
}
}
}
}
struct CustomDotIndicatorView_Previews: PreviewProvider {
@State static var activeIndex: Int = 0
static let indicatorCount: Int = 5
static var previews: some View {
ZStack {
Color.blue.opacity(0.2).ignoresSafeArea(.all)
VStack {
Spacer()
HStack {
Button {
activeIndex -= 1
} label: {
Label("", systemImage: "chevron.left")
}
.padding(.leading, 48)
Spacer()
CustomDotIndicatorView(indicatorCount: indicatorCount,
activeIndex: $activeIndex,
height: 6,
spacing: 12)
Spacer()
Button {
activeIndex += 1
} label: {
Label("", systemImage: "chevron.right")
}
.padding(.trailing, 48)
}
}
}
}
}
So, I have fixed the bug. It is a Preview problem. Because Preview is static, then it won't mutate the Views when we are changing the State. So I need to move the whole `previews` body into a local internal wrapper struct `PreviewWrapper`. So it's like this:
struct CustomDotIndicatorView_Previews: PreviewProvider {
static var previews: some View {
PreviewWrapper()
}
struct PreviewWrapper: View {
@State private var activeIndex: Int = 0
private let indicatorCount: Int = 5
var body: some View {
ZStack {
Color.blue.opacity(0.2).ignoresSafeArea(.all)
VStack {
Spacer()
HStack {
Button {
activeIndex -= 1
} label: {
Label("", systemImage: "chevron.left")
}
.padding(.leading, 48)
Spacer()
CustomDotIndicatorView(indicatorCount: indicatorCount,
activeIndex: $activeIndex,
height: 6,
spacing: 12)
Spacer()
Button {
activeIndex += 1
} label: {
Label("", systemImage: "chevron.right")
}
.padding(.trailing, 48)
}
}
}
}
}
}
Credit to: ChatGPT! Thank you ChatGPT. You're a champ.