Commit 1fc740e4 by Daniel Dahan

storyboard-examples: initial changes to Switch

parent ddc4fd85
...@@ -36,6 +36,7 @@ class RootViewController: UIViewController { ...@@ -36,6 +36,7 @@ class RootViewController: UIViewController {
private var menuButton: IconButton! private var menuButton: IconButton!
private var starButton: IconButton! private var starButton: IconButton!
private var searchButton: IconButton! private var searchButton: IconButton!
private var switchControl: Switch!
open override func viewDidLoad() { open override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
...@@ -74,8 +75,10 @@ class RootViewController: UIViewController { ...@@ -74,8 +75,10 @@ class RootViewController: UIViewController {
tc.toolbar.detail = "Build Beautiful Software" tc.toolbar.detail = "Build Beautiful Software"
tc.toolbar.detailLabel.textAlignment = .left tc.toolbar.detailLabel.textAlignment = .left
switchControl = Switch(state: .off, style:.light, size: .small)
tc.toolbar.leftViews = [menuButton] tc.toolbar.leftViews = [menuButton]
tc.toolbar.rightViews = [starButton, searchButton] tc.toolbar.rightViews = [switchControl, starButton, searchButton]
} }
} }
...@@ -94,7 +94,7 @@ open class Bar: View { ...@@ -94,7 +94,7 @@ open class Bar: View {
/// Grid cell factor. /// Grid cell factor.
@IBInspectable @IBInspectable
open var gridFactor: CGFloat = 24 { open var gridFactor: CGFloat = 12 {
didSet { didSet {
assert(0 < gridFactor, "[Material Error: gridFactor must be greater than 0.]") assert(0 < gridFactor, "[Material Error: gridFactor must be greater than 0.]")
layoutSubviews() layoutSubviews()
...@@ -242,8 +242,8 @@ open class Bar: View { ...@@ -242,8 +242,8 @@ open class Bar: View {
open override func prepare() { open override func prepare() {
super.prepare() super.prepare()
autoresizingMask = .flexibleWidth autoresizingMask = .flexibleWidth
interimSpacePreset = .interimSpace3 interimSpacePreset = .interimSpace4
contentEdgeInsetsPreset = .square1 contentEdgeInsetsPreset = .wideRectangle2
prepareContentView() prepareContentView()
} }
......
...@@ -92,7 +92,7 @@ open class NavigationBar: UINavigationBar { ...@@ -92,7 +92,7 @@ open class NavigationBar: UINavigationBar {
/// Grid cell factor. /// Grid cell factor.
@IBInspectable @IBInspectable
open var gridFactor: CGFloat = 24 { open var gridFactor: CGFloat = 12 {
didSet { didSet {
assert(0 < gridFactor, "[Material Error: gridFactor must be greater than 0.]") assert(0 < gridFactor, "[Material Error: gridFactor must be greater than 0.]")
layoutSubviews() layoutSubviews()
...@@ -294,9 +294,9 @@ open class NavigationBar: UINavigationBar { ...@@ -294,9 +294,9 @@ open class NavigationBar: UINavigationBar {
barStyle = .black barStyle = .black
isTranslucent = false isTranslucent = false
depthPreset = .depth1 depthPreset = .depth1
interimSpacePreset = .interimSpace3 interimSpacePreset = .interimSpace4
contentEdgeInsetsPreset = .square1 contentEdgeInsetsPreset = .wideRectangle2
contentScaleFactor = Device.scale contentScaleFactor = Device.scale
backButtonImage = Icon.cm.arrowBack backButtonImage = Icon.cm.arrowBack
let image = UIImage.imageWithColor(color: Color.clear, size: CGSize(width: 1, height: 1)) let image = UIImage.imageWithColor(color: Color.clear, size: CGSize(width: 1, height: 1))
shadowImage = image shadowImage = image
......
...@@ -62,7 +62,7 @@ public protocol SwitchDelegate { ...@@ -62,7 +62,7 @@ public protocol SwitchDelegate {
@objc(Switch) @objc(Switch)
open class Switch: UIControl { open class Switch: UIControl {
/// An internal reference to the switchState public property. /// An internal reference to the switchState public property.
private var internalSwitchState: SwitchState = .off private var internalSwitchState = SwitchState.off
/// Track thickness. /// Track thickness.
private var trackThickness: CGFloat = 0 private var trackThickness: CGFloat = 0
...@@ -155,7 +155,7 @@ open class Switch: UIControl { ...@@ -155,7 +155,7 @@ open class Switch: UIControl {
} }
/// Track view reference. /// Track view reference.
public private(set) var trackLayer: CAShapeLayer { public private(set) var track: UIView {
didSet { didSet {
prepareTrack() prepareTrack()
} }
...@@ -199,7 +199,7 @@ open class Switch: UIControl { ...@@ -199,7 +199,7 @@ open class Switch: UIControl {
} }
/// Switch style. /// Switch style.
public var switchStyle: SwitchStyle = .dark { public var switchStyle = SwitchStyle.dark {
didSet { didSet {
switch switchStyle { switch switchStyle {
case .light: case .light:
...@@ -225,45 +225,42 @@ open class Switch: UIControl { ...@@ -225,45 +225,42 @@ open class Switch: UIControl {
} }
/// Switch size. /// Switch size.
public var switchSize: SwitchSize = .medium { public var switchSize = SwitchSize.medium {
didSet { didSet {
switch switchSize { switch switchSize {
case .small: case .small:
trackThickness = 13 trackThickness = 12
buttonDiameter = 18 buttonDiameter = 18
frame = CGRect(x: 0, y: 0, width: 30, height: 25)
case .medium: case .medium:
trackThickness = 17 trackThickness = 18
buttonDiameter = 24 buttonDiameter = 24
frame = CGRect(x: 0, y: 0, width: 40, height: 30)
case .large: case .large:
trackThickness = 23 trackThickness = 24
buttonDiameter = 31 buttonDiameter = 32
frame = CGRect(x: 0, y: 0, width: 50, height: 40)
} }
} }
} }
open override var frame: CGRect { open override var frame: CGRect {
didSet { didSet {
layoutSwitch() reload()
} }
} }
open override var bounds: CGRect { open override var bounds: CGRect {
didSet { didSet {
layoutSwitch() reload()
} }
} }
open override var intrinsicContentSize: CGSize { open override var intrinsicContentSize: CGSize {
switch switchSize { switch switchSize {
case .small: case .small:
return CGSize(width: 30, height: 25) return CGSize(width: 24, height: 24)
case .medium: case .medium:
return CGSize(width: 40, height: 30) return CGSize(width: 30, height: 30)
case .large: case .large:
return CGSize(width: 50, height: 40) return CGSize(width: 36, height: 36)
} }
} }
...@@ -272,14 +269,10 @@ open class Switch: UIControl { ...@@ -272,14 +269,10 @@ open class Switch: UIControl {
- Parameter aDecoder: A NSCoder instance. - Parameter aDecoder: A NSCoder instance.
*/ */
public required init?(coder aDecoder: NSCoder) { public required init?(coder aDecoder: NSCoder) {
trackLayer = CAShapeLayer() track = UIView()
button = FabButton() button = FabButton()
super.init(coder: aDecoder) super.init(coder: aDecoder)
prepareTrack() prepare()
prepareButton()
prepareSwitchSize(size: .medium)
prepareSwitchStyle(style: .light)
prepareSwitchState(state: .off)
} }
/** /**
...@@ -290,14 +283,10 @@ open class Switch: UIControl { ...@@ -290,14 +283,10 @@ open class Switch: UIControl {
- Parameter frame: A CGRect instance. - Parameter frame: A CGRect instance.
*/ */
public override init(frame: CGRect) { public override init(frame: CGRect) {
trackLayer = CAShapeLayer() track = UIView()
button = FabButton() button = FabButton()
super.init(frame: frame) super.init(frame: frame)
prepareTrack() prepare()
prepareButton()
prepareSwitchSize(size: .medium)
prepareSwitchStyle(style: .light)
prepareSwitchState(state: .off)
} }
/** /**
...@@ -307,12 +296,11 @@ open class Switch: UIControl { ...@@ -307,12 +296,11 @@ open class Switch: UIControl {
- Parameter size: A SwitchSize value. - Parameter size: A SwitchSize value.
*/ */
public init(state: SwitchState = .off, style: SwitchStyle = .dark, size: SwitchSize = .medium) { public init(state: SwitchState = .off, style: SwitchStyle = .dark, size: SwitchSize = .medium) {
trackLayer = CAShapeLayer() track = UIView()
button = FabButton() button = FabButton()
super.init(frame: CGRect.null) super.init(frame: .zero)
prepareTrack() prepare()
prepareButton() prepareSwitchSize(size: size)
prepareSwitchSize(size: size)
prepareSwitchStyle(style: style) prepareSwitchStyle(style: style)
prepareSwitchState(state: state) prepareSwitchState(state: state)
} }
...@@ -326,7 +314,7 @@ open class Switch: UIControl { ...@@ -326,7 +314,7 @@ open class Switch: UIControl {
Toggle the Switch state, if On will be Off, and if Off will be On. Toggle the Switch state, if On will be Off, and if Off will be On.
- Parameter completion: An Optional completion block. - Parameter completion: An Optional completion block.
*/ */
public func toggle(completion: ((Switch) -> Void)? = nil) { open func toggle(completion: ((Switch) -> Void)? = nil) {
setSwitchState(state: .on == internalSwitchState ? .off : .on, animated: true, completion: completion) setSwitchState(state: .on == internalSwitchState ? .off : .on, animated: true, completion: completion)
} }
...@@ -335,7 +323,7 @@ open class Switch: UIControl { ...@@ -335,7 +323,7 @@ open class Switch: UIControl {
- Parameter on: A bool of whether the switch should be in the on state or not. - Parameter on: A bool of whether the switch should be in the on state or not.
- Parameter animated: A Boolean indicating to set the animation or not. - Parameter animated: A Boolean indicating to set the animation or not.
*/ */
public func setOn(on: Bool, animated: Bool, completion: ((Switch) -> Void)? = nil) { open func setOn(on: Bool, animated: Bool, completion: ((Switch) -> Void)? = nil) {
setSwitchState(state: on ? .on : .off, animated: animated, completion: completion) setSwitchState(state: on ? .on : .off, animated: animated, completion: completion)
} }
...@@ -345,25 +333,27 @@ open class Switch: UIControl { ...@@ -345,25 +333,27 @@ open class Switch: UIControl {
- Parameter animated: A Boolean indicating to set the animation or not. - Parameter animated: A Boolean indicating to set the animation or not.
- Parameter completion: An Optional completion block. - Parameter completion: An Optional completion block.
*/ */
public func setSwitchState(state: SwitchState, animated: Bool = true, completion: ((Switch) -> Void)? = nil) { open func setSwitchState(state: SwitchState, animated: Bool = true, completion: ((Switch) -> Void)? = nil) {
if isEnabled && internalSwitchState != state { guard isEnabled && internalSwitchState != state else {
internalSwitchState = state return
if animated { }
animateToState(state: state) { [weak self] _ in
if let s: Switch = self { internalSwitchState = state
s.sendActions(for: .valueChanged) if animated {
completion?(s) animateToState(state: state) { [weak self] _ in
s.delegate?.switchDidChangeState(control: s, state: s.internalSwitchState) if let s: Switch = self {
} s.sendActions(for: .valueChanged)
} completion?(s)
} else { s.delegate?.switchDidChangeState(control: s, state: s.internalSwitchState)
button.x = .on == state ? self.onPosition : self.offPosition }
styleForState(state: state) }
sendActions(for: .valueChanged) } else {
completion?(self) button.x = .on == state ? self.onPosition : self.offPosition
delegate?.switchDidChangeState(control: self, state: internalSwitchState) styleForState(state: state)
} sendActions(for: .valueChanged)
} completion?(self)
delegate?.switchDidChangeState(control: self, state: internalSwitchState)
}
} }
/** /**
...@@ -373,10 +363,12 @@ open class Switch: UIControl { ...@@ -373,10 +363,12 @@ open class Switch: UIControl {
*/ */
@objc @objc
internal func handleTouchUpOutsideOrCanceled(sender: FabButton, event: UIEvent) { internal func handleTouchUpOutsideOrCanceled(sender: FabButton, event: UIEvent) {
if let v: UITouch = event.touches(for: sender)?.first { guard let v = event.touches(for: sender)?.first else {
let q: CGFloat = sender.x + v.location(in: sender).x - v.previousLocation(in: sender).x return
setSwitchState(state: q > (width - button.width) / 2 ? .on : .off, animated: true) }
}
let q: CGFloat = sender.x + v.location(in: sender).x - v.previousLocation(in: sender).x
setSwitchState(state: q > (width - button.width) / 2 ? .on : .off, animated: true)
} }
/// Handles the TouchUpInside event. /// Handles the TouchUpInside event.
...@@ -392,29 +384,70 @@ open class Switch: UIControl { ...@@ -392,29 +384,70 @@ open class Switch: UIControl {
*/ */
@objc @objc
internal func handleTouchDragInside(sender: FabButton, event: UIEvent) { internal func handleTouchDragInside(sender: FabButton, event: UIEvent) {
if let v = event.touches(for: sender)?.first { guard let v = event.touches(for: sender)?.first else {
let q: CGFloat = max(min(sender.x + v.location(in: sender).x - v.previousLocation(in: sender).x, onPosition), offPosition) return
if q != sender.x { }
sender.x = q
} guard let q: CGFloat = max(min(sender.x + v.location(in: sender).x - v.previousLocation(in: sender).x, onPosition), offPosition) else {
} return
}
guard q != sender.x else {
return
}
sender.x = q
} }
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if true == trackLayer.frame.contains(layer.convert(touches.first!.location(in: self), from: layer)) { guard track.frame.contains(layer.convert(touches.first!.location(in: self), from: layer)) else {
setOn(on: .on != internalSwitchState, animated: true) return
} }
setOn(on: .on != internalSwitchState, animated: true)
} }
/**
Prepares the view instance when intialized. When subclassing,
it is recommended to override the prepare method
to initialize property values and other setup operations.
The super.prepare method should always be called immediately
when subclassing.
*/
open func prepare() {
prepareTrack()
prepareButton()
prepareSwitchSize(size: .medium)
prepareSwitchStyle(style: .light)
prepareSwitchState(state: .off)
}
/// Laout the button and track views.
open func reload() {
var w: CGFloat = intrinsicContentSize.width
let px: CGFloat = (width - w) / 2
track.frame = CGRect(x: px, y: (height - trackThickness) / 2, width: w, height: trackThickness)
track.cornerRadius = min(w, trackThickness) / 2
button.frame = CGRect(x: px, y: (height - buttonDiameter) / 2, width: buttonDiameter, height: buttonDiameter)
onPosition = width - px - buttonDiameter
offPosition = px
if .on == internalSwitchState {
button.x = onPosition
}
}
/// Prepares the track. /// Prepares the track.
private func prepareTrack() { private func prepareTrack() {
layer.addSublayer(trackLayer) addSubview(track)
} }
/// Prepares the button. /// Prepares the button.
private func prepareButton() { private func prepareButton() {
button.pulseAnimation = .none button.pulseColor = Color.white
button.addTarget(self, action: #selector(handleTouchUpInside), for: .touchUpInside) button.addTarget(self, action: #selector(handleTouchUpInside), for: .touchUpInside)
button.addTarget(self, action: #selector(handleTouchDragInside), for: .touchDragInside) button.addTarget(self, action: #selector(handleTouchDragInside), for: .touchDragInside)
button.addTarget(self, action: #selector(handleTouchUpOutsideOrCanceled), for: .touchCancel) button.addTarget(self, action: #selector(handleTouchUpOutsideOrCanceled), for: .touchCancel)
button.addTarget(self, action: #selector(handleTouchUpOutsideOrCanceled), for: .touchUpOutside) button.addTarget(self, action: #selector(handleTouchUpOutsideOrCanceled), for: .touchUpOutside)
...@@ -467,10 +500,10 @@ open class Switch: UIControl { ...@@ -467,10 +500,10 @@ open class Switch: UIControl {
private func updateColorForState(state: SwitchState) { private func updateColorForState(state: SwitchState) {
if .on == state { if .on == state {
button.backgroundColor = buttonOnColor button.backgroundColor = buttonOnColor
trackLayer.backgroundColor = trackOnColor.cgColor track.backgroundColor = trackOnColor
} else { } else {
button.backgroundColor = buttonOffColor button.backgroundColor = buttonOffColor
trackLayer.backgroundColor = trackOffColor.cgColor track.backgroundColor = trackOffColor
} }
} }
...@@ -481,36 +514,10 @@ open class Switch: UIControl { ...@@ -481,36 +514,10 @@ open class Switch: UIControl {
private func updateColorForDisabledState(state: SwitchState) { private func updateColorForDisabledState(state: SwitchState) {
if .on == state { if .on == state {
button.backgroundColor = buttonOnDisabledColor button.backgroundColor = buttonOnDisabledColor
trackLayer.backgroundColor = trackOnDisabledColor.cgColor track.backgroundColor = trackOnDisabledColor
} else { } else {
button.backgroundColor = buttonOffDisabledColor button.backgroundColor = buttonOffDisabledColor
trackLayer.backgroundColor = trackOffDisabledColor.cgColor track.backgroundColor = trackOffDisabledColor
}
}
/// Laout the button and track views.
private func layoutSwitch() {
var w: CGFloat = 0
switch switchSize {
case .small:
w = 30
case .medium:
w = 40
case .large:
w = 50
}
let px: CGFloat = (width - w) / 2
trackLayer.frame = CGRect(x: px, y: (height - trackThickness) / 2, width: w, height: trackThickness)
trackLayer.cornerRadius = min(trackLayer.frame.height, trackLayer.frame.width) / 2
button.frame = CGRect(x: px, y: (height - buttonDiameter) / 2, width: buttonDiameter, height: buttonDiameter)
onPosition = width - px - buttonDiameter
offPosition = px
if .on == internalSwitchState {
button.x = onPosition
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment