Skip to content

Instantly share code, notes, and snippets.

@yageek
Forked from swiftui-lab/TripleToggleStyle.swift
Created September 30, 2022 09:31
Show Gist options
  • Select an option

  • Save yageek/863f98bbcc8ed55ca6a75feb867c9829 to your computer and use it in GitHub Desktop.

Select an option

Save yageek/863f98bbcc8ed55ca6a75feb867c9829 to your computer and use it in GitHub Desktop.

Revisions

  1. @swiftui-lab swiftui-lab revised this gist Nov 1, 2019. 1 changed file with 204 additions and 1 deletion.
    205 changes: 204 additions & 1 deletion TripleToggleStyle.swift
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,206 @@
    // SwiftUI Custom Styles (TripleToggleStyle)
    // https://swiftui-lab.com
    // https://swiftui-lab.com/custom-styling
    // https://swiftui-lab.com/custom-styling

    import SwiftUI

    // MARK: - TripleToggle View
    public struct TripleToggle: View {
    @Environment(\.tripleToggleStyle) var style: AnyTripleToggleStyle

    let label: Text
    @Binding var tripleState: TripleState

    public var body: some View {

    let configuration = TripleToggleStyleConfiguration(tripleState: self._tripleState, label: label)

    return style.makeBody(configuration: configuration)
    }
    }

    // MARK: - Custom Environment Key
    extension EnvironmentValues {
    var tripleToggleStyle: AnyTripleToggleStyle {
    get {
    return self[TripleToggleKey.self]
    }
    set {
    self[TripleToggleKey.self] = newValue
    }
    }
    }

    public struct TripleToggleKey: EnvironmentKey {
    public static let defaultValue: AnyTripleToggleStyle = AnyTripleToggleStyle(DefaultTripleToggleStyle())
    }

    // MARK: - View Extension
    extension View {
    public func tripleToggleStyle<S>(_ style: S) -> some View where S : TripleToggleStyle {
    self.environment(\.tripleToggleStyle, AnyTripleToggleStyle(style))
    }
    }

    // MARK: - Type Erased TripleToggleStyle
    public struct AnyTripleToggleStyle: TripleToggleStyle {
    private let _makeBody: (TripleToggleStyle.Configuration) -> AnyView

    init<ST: TripleToggleStyle>(_ style: ST) {
    self._makeBody = style.makeBodyTypeErased
    }

    public func makeBody(configuration: TripleToggleStyle.Configuration) -> AnyView {
    return self._makeBody(configuration)
    }
    }

    // MARK: - TripleToggleStyle Protocol
    public protocol TripleToggleStyle {
    associatedtype Body : View

    func makeBody(configuration: Self.Configuration) -> Self.Body

    typealias Configuration = TripleToggleStyleConfiguration
    }

    extension TripleToggleStyle {
    func makeBodyTypeErased(configuration: Self.Configuration) -> AnyView {
    AnyView(self.makeBody(configuration: configuration))
    }
    }

    public struct TripleToggleStyleConfiguration {
    @Binding var tripleState: TripleState
    var label: Text
    }

    public enum TripleState: Int {
    case low
    case med
    case high
    }

    // MARK: - DefaultTripleToggleStyle

    public struct DefaultTripleToggleStyle: TripleToggleStyle {

    public func makeBody(configuration: Self.Configuration) -> DefaultTripleToggleStyle.DefaultTripleToggle {
    DefaultTripleToggle(state: configuration.$tripleState, label: configuration.label)
    }

    public struct DefaultTripleToggle: View {
    let width: CGFloat = 50

    @Binding var state: TripleState
    var label: Text

    var stateAlignment: Alignment {
    switch self.state {
    case .low: return .leading
    case .med: return .center
    case .high: return .trailing
    }
    }

    var stateColor: Color {
    switch self.state {
    case .low: return .green
    case .med: return .yellow
    case .high: return .red
    }
    }

    public var body: some View {
    VStack(spacing: 10) {
    label

    ZStack(alignment: self.stateAlignment) {
    RoundedRectangle(cornerRadius: 4)
    .frame(width: self.width, height: self.width / 2)
    .foregroundColor(self.stateColor)

    RoundedRectangle(cornerRadius: 4)
    .frame(width: (self.width / 2) - 4, height: self.width / 2 - 6)
    .padding(4)
    .foregroundColor(.white)
    .onTapGesture {
    withAnimation {
    switch self.state {
    case .low:
    self.$state.wrappedValue = .med
    case .med:
    self.$state.wrappedValue = .high
    case .high:
    self.$state.wrappedValue = .low
    }
    }
    }
    }
    }
    }
    }
    }

    // MARK: - KnobTripleToggleStyle

    public struct KnobTripleToggleStyle: TripleToggleStyle {
    let dotColor: Color

    public func makeBody(configuration: Self.Configuration) -> KnobTripleToggleStyle.KnobTripleToggle {
    KnobTripleToggle(dotColor: dotColor, state: configuration.$tripleState, label: configuration.label)
    }

    public struct KnobTripleToggle: View {
    let dotColor: Color

    @Binding var state: TripleState
    var label: Text

    var angle: Angle {
    switch self.state {
    case .low: return Angle(degrees: -30)
    case .med: return Angle(degrees: 0)
    case .high: return Angle(degrees: 30)
    }
    }

    public var body: some View {
    let g = Gradient(colors: [.white, .gray, .white, .gray, .white, .gray, .white])
    let knobGradient = AngularGradient(gradient: g, center: .center)

    return VStack(spacing: 10) {
    label

    ZStack {

    Circle()
    .fill(knobGradient)

    DotShape()
    .fill(self.dotColor)
    .rotationEffect(self.angle)

    }.frame(width: 150, height: 150)
    .onTapGesture {
    withAnimation {
    switch self.state {
    case .low:
    self.$state.wrappedValue = .med
    case .med:
    self.$state.wrappedValue = .high
    case .high:
    self.$state.wrappedValue = .low
    }
    }
    }
    }
    }
    }

    struct DotShape: Shape {
    func path(in rect: CGRect) -> Path {
    return Path(ellipseIn: CGRect(x: rect.width / 2 - 8, y: 8, width: 16, height: 16))
    }
    }
    }
  2. @swiftui-lab swiftui-lab created this gist Nov 1, 2019.
    3 changes: 3 additions & 0 deletions TripleToggleStyle.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    // SwiftUI Custom Styles (TripleToggleStyle)
    // https://swiftui-lab.com
    // https://swiftui-lab.com/custom-styling