Last active
January 25, 2026 15:51
-
-
Save fxm90/6afe050ac331d8f719029d7fec87e961 to your computer and use it in GitHub Desktop.
A custom `ToggleStyle` that renders a colored, pill-shaped switch with a shadowed circular thumb.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // ColoredToggleStyle.swift | |
| // | |
| // Created by Felix Mau on 29.03.2021. | |
| // Copyright © 2021 Felix Mau. All rights reserved. | |
| // | |
| import SwiftUI | |
| // MARK: - Config | |
| private enum Config { | |
| static let width: CGFloat = 51 | |
| static let height: CGFloat = 31 | |
| static let cornerRadius: CGFloat = 16 | |
| static let circlePadding: CGFloat = 2 | |
| static let animationDuration: TimeInterval = 0.2 | |
| static let shadowColor = Color(.sRGBLinear, white: 0, opacity: 0.15) | |
| static let shadowRadius: CGFloat = 2 | |
| static let shadowOffset = CGPoint(x: 0, y: 1) | |
| } | |
| /// A custom `ToggleStyle` that renders a colored, pill-shaped switch with | |
| /// a shadowed circular thumb. | |
| struct ColoredToggleStyle: ToggleStyle { | |
| // MARK: - Public Properties | |
| let onColor: Color | |
| let offColor: Color | |
| let thumbColor: Color | |
| // MARK: - Initializer | |
| init( | |
| onColor: Color = .blue, | |
| offColor: Color = .gray, | |
| thumbColor: Color = .white, | |
| ) { | |
| self.onColor = onColor | |
| self.offColor = offColor | |
| self.thumbColor = thumbColor | |
| } | |
| // MARK: - Public Methods | |
| func makeBody(configuration: Self.Configuration) -> some View { | |
| HStack { | |
| configuration.label | |
| Spacer() | |
| RoundedRectangle( | |
| cornerRadius: Config.cornerRadius, | |
| style: .circular, | |
| ) | |
| .fill(configuration.isOn ? onColor : offColor) | |
| .frame(width: Config.width, height: Config.height) | |
| .overlay( | |
| ShadowedCircle(fill: thumbColor), | |
| alignment: configuration.isOn ? .trailing : .leading, | |
| ) | |
| .animation(.easeInOut(duration: Config.animationDuration)) | |
| } | |
| .onTapGesture { | |
| configuration.isOn.toggle() | |
| } | |
| } | |
| } | |
| // MARK: - Supporting Types | |
| private struct ShadowedCircle: View { | |
| let fill: Color | |
| var body: some View { | |
| Circle() | |
| .fill(fill) | |
| .aspectRatio(1, contentMode: .fit) | |
| .shadow( | |
| color: Config.shadowColor, | |
| radius: Config.shadowRadius, | |
| x: Config.shadowOffset.x, | |
| y: Config.shadowOffset.y, | |
| ) | |
| .padding(Config.circlePadding) | |
| } | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example Code
The code above will produce the following result.