Skip to content

Instantly share code, notes, and snippets.

@liudasbar
Created September 27, 2021 19:00
Show Gist options
  • Save liudasbar/ff0c74dbd651a0b7239b4d9931a97760 to your computer and use it in GitHub Desktop.
Save liudasbar/ff0c74dbd651a0b7239b4d9931a97760 to your computer and use it in GitHub Desktop.
SwiftUI Custom Segmented Control with animation
struct CustomSegmentedControl: View {
@Binding var arrayOfItems: [Item]
@Binding var selection: Item
@State private var frames: [CGRect] = Array(repeating: .zero, count: 3)
var body: some View {
ScrollView(.horizontal, showsIndicators: false, content: {
HStack(spacing: 0) {
ForEach(arrayOfItems.indices, id: \.self) { index in
Button(
arrayOfItems[index],
action: {
selection = arrayOfItems[index]
})
.font(.body)
.foregroundColor(selection == arrayOfItems[index] ? Color.black : Color.gray)
.padding([.leading, .trailing], 16)
.padding([.top, .bottom], 5)
.buttonStyle(PlainButtonStyle())
.background(
GeometryReader { geo in
Color.clear.onAppear { self.setFrame(index: index, frame: geo.frame(in: .global)) }
}
)
}
}
.padding([.leading, .trailing], 16)
.padding([.top, .bottom], 30)
.background(
Rectangle()
.fill(Color.white)
.cornerRadius(8)
.frame(
width: self.frames[selectionIndex()].width,
height: 30,
alignment: .center
)
.offset(x: self.frames[selectionIndex()].minX - self.frames[0].minX + 16),
alignment: .leading
)
.animation(.easeInOut(duration: 0.2))
})
}
private func selectionIndex() -> Int {
for (index, item) in arrayOfItems.enumerated() where item == selection {
return index
}
return 0
}
private func setFrame(index: Int, frame: CGRect) {
self.frames[index] = frame
}
}
@liudasbar
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment