DoublePickerRow.swift 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. //
  2. // MultiplePickerRow.swift
  3. // Eureka
  4. //
  5. // Created by Mathias Claassen on 5/8/18.
  6. // Copyright © 2018 Xmartlabs. All rights reserved.
  7. //
  8. import Foundation
  9. import UIKit
  10. public struct Tuple<A: Equatable, B: Equatable> {
  11. public let a: A
  12. public let b: B
  13. public init(a: A, b: B) {
  14. self.a = a
  15. self.b = b
  16. }
  17. }
  18. extension Tuple: Equatable {}
  19. public func == <A: Equatable, B: Equatable>(lhs: Tuple<A, B>, rhs: Tuple<A, B>) -> Bool {
  20. return lhs.a == rhs.a && lhs.b == rhs.b
  21. }
  22. // MARK: MultiplePickerCell
  23. open class DoublePickerCell<A, B> : _PickerCell<Tuple<A, B>> where A: Equatable, B: Equatable {
  24. private var pickerRow: _DoublePickerRow<A, B>? { return row as? _DoublePickerRow<A, B> }
  25. public required init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
  26. super.init(style: style, reuseIdentifier: reuseIdentifier)
  27. }
  28. required public init?(coder aDecoder: NSCoder) {
  29. super.init(coder: aDecoder)
  30. }
  31. open override func update() {
  32. super.update()
  33. if let selectedValue = pickerRow?.value, let indexA = pickerRow?.firstOptions().firstIndex(of: selectedValue.a),
  34. let indexB = pickerRow?.secondOptions(selectedValue.a).firstIndex(of: selectedValue.b) {
  35. picker.selectRow(indexA, inComponent: 0, animated: true)
  36. picker.selectRow(indexB, inComponent: 1, animated: true)
  37. }
  38. }
  39. open override func numberOfComponents(in pickerView: UIPickerView) -> Int {
  40. return 2
  41. }
  42. open override func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
  43. guard let pickerRow = pickerRow else { return 0 }
  44. return component == 0 ? pickerRow.firstOptions().count : pickerRow.secondOptions(pickerRow.selectedFirst()).count
  45. }
  46. open override func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
  47. guard let pickerRow = pickerRow else { return "" }
  48. if component == 0 {
  49. return pickerRow.displayValueForFirstRow(pickerRow.firstOptions()[row])
  50. } else {
  51. return pickerRow.displayValueForSecondRow(pickerRow.secondOptions(pickerRow.selectedFirst())[row])
  52. }
  53. }
  54. open override func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
  55. guard let pickerRow = pickerRow else { return }
  56. if component == 0 {
  57. let a = pickerRow.firstOptions()[row]
  58. if let value = pickerRow.value {
  59. guard value.a != a else {
  60. return
  61. }
  62. if pickerRow.secondOptions(a).contains(value.b) {
  63. pickerRow.value = Tuple(a: a, b: value.b)
  64. pickerView.reloadComponent(1)
  65. return
  66. } else {
  67. pickerRow.value = Tuple(a: a, b: pickerRow.secondOptions(a)[0])
  68. }
  69. } else {
  70. pickerRow.value = Tuple(a: a, b: pickerRow.secondOptions(a)[0])
  71. }
  72. pickerView.reloadComponent(1)
  73. pickerView.selectRow(0, inComponent: 1, animated: true)
  74. } else {
  75. let a = pickerRow.selectedFirst()
  76. pickerRow.value = Tuple(a: a, b: pickerRow.secondOptions(a)[row])
  77. }
  78. }
  79. }
  80. // MARK: PickerRow
  81. open class _DoublePickerRow<A, B> : Row<DoublePickerCell<A, B>> where A: Equatable, B: Equatable {
  82. /// Options for first component. Will be called often so should be O(1)
  83. public var firstOptions: (() -> [A]) = {[]}
  84. /// Options for second component given the selected value from the first component. Will be called often so should be O(1)
  85. public var secondOptions: ((A) -> [B]) = {_ in []}
  86. /// Modify the displayed values for the first picker row.
  87. public var displayValueForFirstRow: ((A) -> (String)) = { a in return String(describing: a) }
  88. /// Modify the displayed values for the second picker row.
  89. public var displayValueForSecondRow: ((B) -> (String)) = { b in return String(describing: b) }
  90. required public init(tag: String?) {
  91. super.init(tag: tag)
  92. }
  93. func selectedFirst() -> A {
  94. return value?.a ?? firstOptions()[0]
  95. }
  96. }
  97. /// A generic row where the user can pick an option from a picker view
  98. public final class DoublePickerRow<A, B>: _DoublePickerRow<A, B>, RowType where A: Equatable, B: Equatable {
  99. required public init(tag: String?) {
  100. super.init(tag: tag)
  101. }
  102. }