Last active
          October 29, 2020 08:48 
        
      - 
      
- 
        Save onevcat/40f21b41a6b1ffa06ceb9f3ee0470bf3 to your computer and use it in GitHub Desktop. 
Revisions
- 
        onevcat revised this gist Oct 21, 2020 . No changes.There are no files selected for viewing
- 
        onevcat created this gist Oct 21, 2020 .There are no files selected for viewingThis 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,132 @@ //: A UIKit based Playground for presenting user interface import UIKit import PlaygroundSupport public protocol TrafficLightOption { associatedtype Value /// 默认的选项值 static var defaultValue: Value { get } } extension TrafficLight { public enum GreenLightColor: TrafficLightOption { case green case turquoise public static let defaultValue: GreenLightColor = .green } } extension TrafficLight { public var preferredGreenLightColor: TrafficLight.GreenLightColor { get { self[option: GreenLightColor.self] } set { self[option: GreenLightColor.self] = newValue } } } public class TrafficLight { public enum State { case stop case proceed case caution } private var options = [ObjectIdentifier: Any]() public subscript<T: TrafficLightOption>(option type: T.Type) -> T.Value { get { options[ObjectIdentifier(type)] as? T.Value ?? type.defaultValue } set { options[ObjectIdentifier(type)] = newValue } } public private(set) var state: State = .stop { didSet { onStateChanged?(state) } } public var onStateChanged: ((State) -> Void)? public var stopDuration = 4.0 public var proceedDuration = 6.0 public var cautionDuration = 1.5 private var timer: Timer? public func start() { guard timer == nil else { return } turnState(.stop) } public func stop() { timer?.invalidate() timer = nil } private func turnState(_ state: State) { switch state { case .proceed: timer = Timer.scheduledTimer(withTimeInterval: proceedDuration, repeats: false) { _ in self.turnState(.caution) } case .caution: timer = Timer.scheduledTimer(withTimeInterval: cautionDuration, repeats: false) { _ in self.turnState(.stop) } case .stop: timer = Timer.scheduledTimer(withTimeInterval: stopDuration, repeats: false) { _ in self.turnState(.proceed) } } self.state = state } } class MyViewController : UIViewController { var light: TrafficLight! override func loadView() { let view = UIView() view.backgroundColor = .white self.view = view light = TrafficLight() light.preferredGreenLightColor = .turquoise light.onStateChanged = { [weak self, weak light] state in guard let self = self, let light = light else { return } let color: UIColor switch state { case .proceed: color = light.preferredGreenLightColor.color case .caution: color = .yellow case .stop: color = .red } UIView.animate(withDuration: 0.25) { self.view.backgroundColor = color } } light.start() } deinit { light.stop() } } extension TrafficLight.GreenLightColor { var color: UIColor { switch self { case .green: return .green case .turquoise: return UIColor(red: 0.25, green: 0.88, blue: 0.82, alpha: 1.00) } } } // Present the view controller in the Live View window PlaygroundPage.current.liveView = MyViewController()