Skip to content

Instantly share code, notes, and snippets.

@maysamsh
Last active December 17, 2024 03:45
Show Gist options
  • Select an option

  • Save maysamsh/327c77e3f3c98ec29faf026ed5bd143e to your computer and use it in GitHub Desktop.

Select an option

Save maysamsh/327c77e3f3c98ec29faf026ed5bd143e to your computer and use it in GitHub Desktop.
A custom segment control for SwiftUI
//
// SegmentedControl.swift
//
// Created by Maysam Shahsavari on 2024-12-12.
//
// Original code: https://github.com/NilCoalescing/SwiftUI-Code-Examples/blob/main/Custom-Segmented-Control-with-Matched-Geometry-Effect/CustomSegmentedControl.swift
// Example code for the original code: https://nilcoalescing.com/blog/CustomSegmentedControlWithMatchedGeometryEffect/
// Final document: https://maysamsh.me/2024/12/16/animated-segmented-control/
import SwiftUI
/// A type that provides a title for contr
protocol SegmentedControlType: CaseIterable {
var title: String { get }
}
enum SampleOptions: Identifiable, CustomStringConvertible, SegmentedControlType, Hashable {
var id: Self { self }
case option1
case option2
var title: String {
switch self {
case .option1:
return "Option 1"
case .option2:
return "Option 2"
}
}
var description: String {
return title
}
}
struct SegmentedControl<T: SegmentedControlType>: View where T: Identifiable, T: Hashable, T.AllCases: RandomAccessCollection {
@Binding private var selection: T
@Namespace private var segmentedControl
init(selection: Binding<T>) {
self._selection = selection
}
var body: some View {
HStack {
ForEach(T.allCases) { state in
Button {
withAnimation {
selection = state
}
} label: {
Text(state.title)
.padding(10)
}
.matchedGeometryEffect(
id: state,
in: segmentedControl
)
}
}
.background(
Capsule()
.fill(.background.tertiary)
.matchedGeometryEffect(
id: selection,
in: segmentedControl,
isSource: false
)
)
.padding(6)
.background(.indigo)
.clipShape(
Capsule()
)
.buttonStyle(.plain)
}
}
#Preview {
@Previewable @State var options: SampleOptions = .option1
SegmentedControl(selection: $options)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment