Skip to content

Instantly share code, notes, and snippets.

@fxm90
Last active January 25, 2026 15:51
Show Gist options
  • Select an option

  • Save fxm90/6afe050ac331d8f719029d7fec87e961 to your computer and use it in GitHub Desktop.

Select an option

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.
//
// 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)
}
}
@fxm90
Copy link
Author

fxm90 commented May 25, 2021

Example Code

struct ContentView: View {

  // MARK: - Private Properties

  @State
  private var isOriginalToggleOn = false

  @State
  private var isCustomToggleOn = false

  // MARK: - Render

  var body: some View {
    List {
      Section(header: Text("Custom Toggle Style")) {
        Toggle("Original Toggle", isOn: $isOriginalToggleOn)

        Toggle("Custom Toggle", isOn: $isCustomToggleOn)
          .toggleStyle(ColoredToggleStyle())
      }
    }
    .listStyle(InsetGroupedListStyle())
  }
}

The code above will produce the following result.

Off-State On-State
CustomColorToggle--Off CustomColorToggle

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