Last active
May 10, 2023 07:45
-
-
Save satishVekariya/74cb6423643d621bbf200b787c7db6d0 to your computer and use it in GitHub Desktop.
A custom toggle style
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
| import SwiftUI | |
| /// Custom toggle style | |
| /// | |
| /// Reference: | |
| /// - https://www.bigmountainstudio.com/community/public/posts/11825-swiftui-togglestyle-customizing-the-toggle | |
| struct ColoredToggleStyle: ToggleStyle { | |
| let labelFont = Font.system(size: 14, weight: .regular) | |
| let labelColor = Color.secondaryMain | |
| let onColor = Color.semanticsSuccessMain | |
| let offColor = Color.terrainHue2 | |
| let thumbColor = Color.commonWhite | |
| @State private var isDragging = false | |
| func makeBody(configuration: Self.Configuration) -> some View { | |
| HStack { | |
| configuration.label // The text (or view) portion of the Toggle | |
| .font(labelFont) | |
| .foregroundColor(labelColor) | |
| Spacer() | |
| RoundedRectangle(cornerRadius: Const.switchCornerRadius, style: .circular) | |
| .fill(configuration.isOn ? onColor : offColor) | |
| .frame(width: Const.switchSize.width, height: Const.switchSize.height) | |
| .overlay(thumbView(configuration)) | |
| .animation(Animation.easeInOut(duration: 0.2), value: configuration.isOn) | |
| .gesture(dragAndTapGesture(configuration)) | |
| } | |
| } | |
| func dragAndTapGesture(_ config: Self.Configuration) -> some Gesture { | |
| ExclusiveGesture( | |
| DragGesture(minimumDistance: 1) | |
| .onChanged { value in | |
| isDragging = true | |
| handleDrag(config, value: value) | |
| } | |
| .onEnded { value in | |
| isDragging = false | |
| handleDrag(config, value: value) | |
| } | |
| , | |
| TapGesture() | |
| .onEnded { | |
| config.isOn.toggle() | |
| } | |
| ) | |
| } | |
| private func thumbView(_ configuration: Self.Configuration) -> some View { | |
| Circle() | |
| .fill(thumbColor) | |
| .shadow(radius: 1, x: 0, y: 1) | |
| .padding(1.5) | |
| .offset(x: configuration.isOn ? Const.thumbXOffset: -Const.thumbXOffset) | |
| .scaleEffect(x: isDragging ? 1.1 : 1, anchor: configuration.isOn ? .trailing : .leading) | |
| .animation(Animation.easeInOut(duration: 0.1), value: isDragging) | |
| } | |
| private func handleDrag(_ config: Self.Configuration, value: DragGesture.Value) { | |
| guard value.translation.width != .zero else { | |
| return | |
| } | |
| /// Bounded value | |
| let value = min(max(value.translation.width, -Const.switchSize.width), Const.switchSize.width) | |
| /// Translation progress within view's bounds | |
| let progress = value/Const.switchSize.width | |
| /// Check against the minimum progress | |
| guard abs(progress) > 0.5 else { | |
| return | |
| } | |
| /// Check direction | |
| switch progress.sign { | |
| case .plus: /// Dragging towards left (on) | |
| /// Check switch is not already in on state | |
| if config.isOn == false { | |
| config.isOn.toggle() | |
| } | |
| case .minus: /// Dragging towards right (off) | |
| /// Check switch is not already in off state | |
| if config.isOn == true { | |
| config.isOn.toggle() | |
| } | |
| } | |
| } | |
| enum Const { | |
| static let switchSize = CGSize(width: 50, height: 29) | |
| static let switchCornerRadius: CGFloat = 16 | |
| static let thumbXOffset: CGFloat = 10 | |
| } | |
| } | |
| public struct ToggleSwitch: View { | |
| let isOn: Binding<Bool> | |
| let text: String? | |
| let axID: String | |
| public init(isOn: Binding<Bool>, text: String? = nil, axID: String = "Toggle_switch") { | |
| self.isOn = isOn | |
| self.text = text | |
| self.axID = axID | |
| } | |
| public var body: some View { | |
| Toggle(isOn: isOn) { | |
| if let text { | |
| Text(text) | |
| .font(.system(size: 14, weight: .regular)) | |
| .foregroundColor(.secondaryMain) | |
| .accessibilityIdentifier(axID + "_label") | |
| } | |
| } | |
| .toggleStyle(ColoredToggleStyle()) | |
| .accessibilityIdentifier(axID) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment