StepperRow.swift 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //
  2. // StepperRow.swift
  3. // Eureka
  4. //
  5. // Created by Andrew Holt on 3/4/16.
  6. // Copyright © 2016 Xmartlabs. All rights reserved.
  7. //
  8. import UIKit
  9. // MARK: StepperCell
  10. open class StepperCell: Cell<Double>, CellType {
  11. @IBOutlet open weak var stepper: UIStepper!
  12. @IBOutlet open weak var valueLabel: UILabel!
  13. @IBOutlet open weak var titleLabel: UILabel!
  14. private var awakeFromNibCalled = false
  15. required public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  16. super.init(style: .value1, reuseIdentifier: reuseIdentifier)
  17. NotificationCenter.default.addObserver(forName: UIContentSizeCategory.didChangeNotification, object: nil, queue: nil) { [weak self] _ in
  18. guard let me = self else { return }
  19. if me.shouldShowTitle {
  20. me.titleLabel = me.textLabel
  21. me.setNeedsUpdateConstraints()
  22. }
  23. }
  24. }
  25. required public init?(coder aDecoder: NSCoder) {
  26. super.init(coder: aDecoder)
  27. awakeFromNibCalled = true
  28. }
  29. open override func setup() {
  30. super.setup()
  31. if !awakeFromNibCalled {
  32. let title = textLabel
  33. textLabel?.translatesAutoresizingMaskIntoConstraints = false
  34. textLabel?.setContentHuggingPriority(UILayoutPriority(rawValue: 500), for: .horizontal)
  35. self.titleLabel = title
  36. let stepper = UIStepper()
  37. stepper.translatesAutoresizingMaskIntoConstraints = false
  38. stepper.setContentHuggingPriority(UILayoutPriority(rawValue: 500), for: .horizontal)
  39. self.stepper = stepper
  40. if shouldShowTitle {
  41. contentView.addSubview(titleLabel)
  42. }
  43. setupValueLabel()
  44. contentView.addSubview(stepper)
  45. setNeedsUpdateConstraints()
  46. }
  47. selectionStyle = .none
  48. stepper.addTarget(self, action: #selector(StepperCell.valueChanged), for: .valueChanged)
  49. }
  50. open func setupValueLabel() {
  51. let label = UILabel()
  52. label.translatesAutoresizingMaskIntoConstraints = false
  53. label.setContentHuggingPriority(UILayoutPriority(500), for: .horizontal)
  54. label.adjustsFontSizeToFitWidth = true
  55. label.minimumScaleFactor = 0.5
  56. self.valueLabel = label
  57. contentView.addSubview(valueLabel)
  58. }
  59. open override func update() {
  60. super.update()
  61. detailTextLabel?.text = nil
  62. stepper.isEnabled = !row.isDisabled
  63. titleLabel.isHidden = !shouldShowTitle
  64. stepper.value = row.value ?? 0
  65. stepper.alpha = row.isDisabled ? 0.3 : 1.0
  66. valueLabel?.textColor = tintColor
  67. valueLabel?.alpha = row.isDisabled ? 0.3 : 1.0
  68. valueLabel?.text = row.displayValueFor?(row.value)
  69. }
  70. @objc func valueChanged() {
  71. row.value = stepper.value
  72. row.updateCell()
  73. }
  74. var shouldShowTitle: Bool {
  75. return row?.title?.isEmpty == false
  76. }
  77. private var stepperRow: StepperRow {
  78. return row as! StepperRow
  79. }
  80. deinit {
  81. stepper.removeTarget(self, action: nil, for: .allEvents)
  82. guard !awakeFromNibCalled else { return }
  83. NotificationCenter.default.removeObserver(self, name: UIContentSizeCategory.didChangeNotification, object: nil)
  84. }
  85. open override func updateConstraints() {
  86. customConstraints()
  87. super.updateConstraints()
  88. }
  89. open var dynamicConstraints = [NSLayoutConstraint]()
  90. open func customConstraints() {
  91. guard !awakeFromNibCalled else { return }
  92. contentView.removeConstraints(dynamicConstraints)
  93. dynamicConstraints = []
  94. var views: [String : Any] = ["titleLabel": titleLabel!, "stepper": stepper!, "valueLabel": valueLabel!]
  95. let metrics = ["spacing": 15.0]
  96. valueLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
  97. titleLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
  98. let title = shouldShowTitle ? "[titleLabel]-(>=15@250)-" : ""
  99. if let imageView = imageView, let _ = imageView.image {
  100. views["imageView"] = imageView
  101. let hContraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-[imageView]-(15)-\(title)[valueLabel]-[stepper]-|", options: .alignAllCenterY, metrics: metrics, views: views)
  102. imageView.translatesAutoresizingMaskIntoConstraints = false
  103. dynamicConstraints.append(contentsOf: hContraints)
  104. } else {
  105. let hContraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-\(title)[valueLabel]-[stepper]-|", options: .alignAllCenterY, metrics: metrics, views: views)
  106. dynamicConstraints.append(contentsOf: hContraints)
  107. }
  108. let vContraint = NSLayoutConstraint(item: stepper!, attribute: .centerY, relatedBy: .equal, toItem: contentView, attribute: .centerY, multiplier: 1, constant: 0)
  109. dynamicConstraints.append(vContraint)
  110. contentView.addConstraints(dynamicConstraints)
  111. }
  112. }
  113. // MARK: StepperRow
  114. open class _StepperRow: Row<StepperCell> {
  115. required public init(tag: String?) {
  116. super.init(tag: tag)
  117. displayValueFor = { value in
  118. guard let value = value else { return nil }
  119. return DecimalFormatter().string(from: NSNumber(value: value)) }
  120. }
  121. }
  122. /// Double row that has a UIStepper as accessoryType
  123. public final class StepperRow: _StepperRow, RowType {
  124. required public init(tag: String?) {
  125. super.init(tag: tag)
  126. }
  127. }