IBNumberEditText.swift 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. //
  2. // IBNumberEditText.swift
  3. // MTP2_iOS
  4. //
  5. // Created by Handy_Cao on 2018/11/10.
  6. // Copyright © 2018 Muchinfo. All rights reserved.
  7. //
  8. import UIKit
  9. /// 输入框按钮类型
  10. ///
  11. /// - Add: 加
  12. /// - Subtract: 减
  13. enum NumberInputViewButtonType {
  14. case Add
  15. case Subtract
  16. }
  17. @IBDesignable
  18. class IBNumberEditText: UIView {
  19. // MARK: - 属性列表
  20. /// 减号
  21. @IBOutlet weak var minusBtn: IBButton!
  22. /// 加号
  23. @IBOutlet weak var addBtn: IBButton!
  24. /// 输入框
  25. @IBOutlet weak var numberField: IBTextField!
  26. /// 定义container为DemoView的子view, 以便更方便的封装xib
  27. @IBOutlet weak var containerView: UIView!
  28. /// 小数位,如果需要则设置
  29. var decimalPlace: Int?
  30. /// 增量(默认值为1)
  31. var incrementIntNum = 1
  32. var incrementDoubleNum: Double = 1
  33. /// 最大值
  34. var maxIntNum = Int.max
  35. var maxDoubleNum = Double(Int.max)
  36. /// 最小值
  37. var minIntNum = 0
  38. var minDoubleNum = 0.0
  39. /// 是否循环
  40. var isWarp = false
  41. /// 不允许交互
  42. override var isUserInteractionEnabled: Bool {
  43. didSet {
  44. addBtn.layer.borderColor = UIColorFromHex(rgbValue: isUserInteractionEnabled ? 0x333333 : 0xcccccc).cgColor
  45. minusBtn.layer.borderColor = UIColorFromHex(rgbValue: isUserInteractionEnabled ? 0x333333 : 0xcccccc).cgColor
  46. numberField.textColor = UIColorFromHex(rgbValue: isUserInteractionEnabled ? 0x3384F3 : 0x999999)
  47. }
  48. }
  49. /// 代理
  50. weak var delegate: IBNumberEditTextDelegate?
  51. /// 需要的值类型 1: Int 2: Double
  52. var valueType = 1 {
  53. didSet {
  54. switch valueType {
  55. case 1:
  56. numberField.keyboardType = .numberPad
  57. default:
  58. numberField.keyboardType = .decimalPad
  59. }
  60. }
  61. }
  62. /// 当前Int值
  63. var currentIntNumbers: Int {
  64. get {
  65. return Int(numberField.text!) ?? 0
  66. }
  67. set {
  68. if newValue > maxIntNum {
  69. numberField.text = String(maxIntNum)
  70. } else {
  71. numberField.text = String(newValue)
  72. }
  73. delegate?.IBNumberEditText(textField: numberField)
  74. }
  75. }
  76. /// 当前Double值
  77. var currentDoubleNumbers: Double {
  78. get {
  79. if let decimalPlace = decimalPlace {
  80. /// FIXME: - 暂时用于解决浮点数计算失真问题
  81. return Double(String(format: "%.\(decimalPlace)f", Double(numberField.text!) ?? 0)) ?? 0
  82. } else {
  83. return Double(numberField.text!) ?? 0
  84. }
  85. }
  86. set {
  87. if let decimalPlace = decimalPlace {
  88. if Double(Int(newValue)) == newValue {
  89. numberField.text = newValue.toString(reserve: decimalPlace)
  90. } else {
  91. numberField.text = String(format: "%.\(decimalPlace)f", newValue)
  92. }
  93. } else {
  94. if Double(Int(newValue)) == newValue {
  95. numberField.text = newValue.toString(reserve: decimalPlace ?? 0)
  96. } else {
  97. numberField.text = newValue.toString(reserve: decimalPlace ?? 0)
  98. }
  99. }
  100. delegate?.IBNumberEditText(textField: numberField)
  101. }
  102. }
  103. // MARK: - 生命周期
  104. override init(frame: CGRect) {
  105. super.init(frame: frame)
  106. initViewFromNib()
  107. }
  108. required init?(coder aDecoder: NSCoder) {
  109. super.init(coder: aDecoder)
  110. initViewFromNib()
  111. }
  112. private func initViewFromNib() {
  113. /// 需要这句代码,不能直接写UINib(nibName: "MyView", bundle: nil),不然不能在storyboard中显示
  114. let bundle = Bundle.init(for: self.classForCoder)
  115. let nib = UINib(nibName: "NumberEditText", bundle: bundle)
  116. containerView = nib.instantiate(withOwner: self, options: nil)[0] as? UIView
  117. containerView.frame = bounds
  118. addSubview(containerView)
  119. }
  120. override func awakeFromNib() {
  121. NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextField.textDidChangeNotification, object: numberField)
  122. }
  123. @objc fileprivate func valueChanged() {
  124. delegate?.IBNumberEditText(textField: numberField)
  125. }
  126. deinit {
  127. NotificationCenter.default.removeObserver(self)
  128. }
  129. // MARK: - 交互相关
  130. @IBAction func onButtonPressed(_ sender: IBButton) {
  131. switch sender {
  132. case addBtn:
  133. if valueType == 1 {
  134. if currentIntNumbers < maxIntNum {
  135. currentIntNumbers += incrementIntNum
  136. } else if isWarp {
  137. currentIntNumbers = minIntNum
  138. }
  139. } else {
  140. if currentDoubleNumbers < maxDoubleNum {
  141. currentDoubleNumbers += incrementDoubleNum
  142. } else if isWarp {
  143. currentDoubleNumbers = minDoubleNum
  144. }
  145. }
  146. /// 出发代理
  147. guard let delegate = self.delegate else { return }
  148. delegate.numberInputView(self, .Add)
  149. case minusBtn:
  150. if valueType == 1 {
  151. if currentIntNumbers > minIntNum {
  152. currentIntNumbers -= incrementIntNum
  153. } else if isWarp {
  154. currentIntNumbers = maxIntNum
  155. }
  156. } else {
  157. if currentDoubleNumbers > minDoubleNum {
  158. currentDoubleNumbers -= incrementDoubleNum
  159. } else if isWarp {
  160. currentDoubleNumbers = maxDoubleNum
  161. }
  162. }
  163. /// 出发代理
  164. guard let delegate = self.delegate else { return }
  165. delegate.numberInputView(self, .Subtract)
  166. default:
  167. break
  168. }
  169. /// 通知值变化
  170. delegate?.IBNumberEditText(textField: numberField)
  171. }
  172. /// 是否置为不可用
  173. var isDisabled = false {
  174. didSet {
  175. self.isUserInteractionEnabled = !isDisabled
  176. addBtn.isEnabled = !isDisabled
  177. minusBtn.isEnabled = !isDisabled
  178. }
  179. }
  180. }
  181. extension IBNumberEditText: UITextFieldDelegate {
  182. func textFieldDidBeginEditing(_ textField: UITextField) {
  183. if Double(textField.text!) == 0 {
  184. textField.text = ""
  185. }
  186. }
  187. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  188. /// 解决删除按钮失效问题
  189. if (range.length == 1 && string.count == 0) {
  190. return true
  191. }
  192. if let decimalPlace = decimalPlace,
  193. let num = textField.text?.split(separator: ".").compactMap(String.init),
  194. num.count == 2, num[1].count == decimalPlace {
  195. return false
  196. }
  197. return true
  198. }
  199. func textFieldDidEndEditing(_ textField: UITextField) {
  200. /// 类型为整数型
  201. if valueType == 1 {
  202. self.currentIntNumbers = Int(self.currentIntNumbers/self.incrementIntNum)*Int(self.incrementIntNum)
  203. }
  204. /// numberInputViewDidEndEditing
  205. delegate?.numberInputViewDidEndEditing(self)
  206. }
  207. }
  208. protocol IBNumberEditTextDelegate: class {
  209. /// valueChanged 触发
  210. ///
  211. /// - Parameter textField: 值变化的输入框
  212. func IBNumberEditText(textField: UITextField)
  213. /// 按钮点击出发
  214. ///
  215. /// - Parameters:
  216. /// - buttonType: 按钮类型
  217. func numberInputView(_ numberInputView: IBNumberEditText, _ buttonType: NumberInputViewButtonType)
  218. /// numberInputViewDidEndEditing
  219. /// - Parameter numberInputView: numberInputView
  220. func numberInputViewDidEndEditing(_ numberInputView: IBNumberEditText)
  221. }