IBNumberEditText.swift 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. /// 增量值
  33. var incrementDoubleNum: Double = 1.0
  34. /// 最大值
  35. var maxIntNum = Int.max
  36. /// 最大值
  37. var maxDoubleNum = Double(Int.max)
  38. /// 最小值
  39. var minIntNum = 0
  40. var minDoubleNum = 0.0
  41. /// 是否循环
  42. var isWarp = false
  43. /// 不允许交互
  44. override var isUserInteractionEnabled: Bool {
  45. didSet {
  46. addBtn.setBackgroundImage(UIImage(named: isUserInteractionEnabled ? "add_enable" : "add_unenable"), for: .normal)
  47. minusBtn.setBackgroundImage(UIImage(named: isUserInteractionEnabled ? "sub_enable" : "sub_unenable"), for: .normal)
  48. numberField.textColor = UIColorFromHex(rgbValue: isUserInteractionEnabled ? 0x3384F3 : 0x999999)
  49. }
  50. }
  51. /// 代理
  52. weak var delegate: IBNumberEditTextDelegate?
  53. /// 需要的值类型 1: Int 2: Double
  54. var valueType = 1 {
  55. didSet {
  56. switch valueType {
  57. case 1:
  58. numberField.keyboardType = .numberPad
  59. default:
  60. numberField.keyboardType = .decimalPad
  61. }
  62. }
  63. }
  64. /// 当前Int值
  65. var currentIntNumbers: Int {
  66. get {
  67. return Int(numberField.text!) ?? 0
  68. }
  69. set {
  70. if newValue > maxIntNum {
  71. numberField.text = String(maxIntNum)
  72. } else {
  73. numberField.text = String(newValue)
  74. }
  75. delegate?.IBNumberEditText(textField: numberField)
  76. }
  77. }
  78. /// 当前Double值
  79. var currentDoubleNumbers: Double {
  80. get {
  81. if let decimalPlace = decimalPlace {
  82. /// FIXME: - 暂时用于解决浮点数计算失真问题
  83. return Double(String(format: "%.\(decimalPlace)f", Double(numberField.text!) ?? 0)) ?? 0
  84. } else {
  85. return Double(numberField.text!) ?? 0
  86. }
  87. }
  88. set {
  89. if let decimalPlace = decimalPlace {
  90. if Double(Int(newValue)) == newValue {
  91. numberField.text = newValue.toString(reserve: decimalPlace)
  92. } else {
  93. numberField.text = String(format: "%.\(decimalPlace)f", newValue)
  94. }
  95. } else {
  96. if Double(Int(newValue)) == newValue {
  97. numberField.text = newValue.toString(reserve: decimalPlace ?? 0)
  98. } else {
  99. numberField.text = newValue.toString(reserve: decimalPlace ?? 0)
  100. }
  101. }
  102. delegate?.IBNumberEditText(textField: numberField)
  103. }
  104. }
  105. // MARK: - 生命周期
  106. override init(frame: CGRect) {
  107. super.init(frame: frame)
  108. initViewFromNib()
  109. }
  110. required init?(coder aDecoder: NSCoder) {
  111. super.init(coder: aDecoder)
  112. initViewFromNib()
  113. }
  114. private func initViewFromNib() {
  115. /// 需要这句代码,不能直接写UINib(nibName: "MyView", bundle: nil),不然不能在storyboard中显示
  116. let bundle = Bundle.init(for: self.classForCoder)
  117. let nib = UINib(nibName: "NumberEditText", bundle: bundle)
  118. containerView = nib.instantiate(withOwner: self, options: nil)[0] as? UIView
  119. containerView.frame = bounds
  120. addSubview(containerView)
  121. }
  122. override func awakeFromNib() {
  123. NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextField.textDidChangeNotification, object: numberField)
  124. }
  125. @objc fileprivate func valueChanged() {
  126. delegate?.IBNumberEditText(textField: numberField)
  127. }
  128. deinit {
  129. NotificationCenter.default.removeObserver(self)
  130. }
  131. // MARK: - 交互相关
  132. @IBAction func onButtonPressed(_ sender: IBButton) {
  133. switch sender {
  134. case addBtn:
  135. if valueType == 1 {
  136. if currentIntNumbers < maxIntNum {
  137. currentIntNumbers += incrementIntNum
  138. } else if isWarp {
  139. currentIntNumbers = minIntNum
  140. }
  141. } else {
  142. if currentDoubleNumbers < maxDoubleNum {
  143. currentDoubleNumbers += incrementDoubleNum
  144. } else if isWarp {
  145. currentDoubleNumbers = minDoubleNum
  146. }
  147. }
  148. /// 出发代理
  149. guard let delegate = self.delegate else { return }
  150. delegate.numberInputView(self, .Add)
  151. case minusBtn:
  152. if valueType == 1 {
  153. if currentIntNumbers > minIntNum {
  154. currentIntNumbers -= incrementIntNum
  155. } else if isWarp {
  156. currentIntNumbers = maxIntNum
  157. }
  158. } else {
  159. if currentDoubleNumbers > minDoubleNum {
  160. currentDoubleNumbers -= incrementDoubleNum
  161. } else if isWarp {
  162. currentDoubleNumbers = maxDoubleNum
  163. }
  164. }
  165. /// 出发代理
  166. guard let delegate = self.delegate else { return }
  167. delegate.numberInputView(self, .Subtract)
  168. default:
  169. break
  170. }
  171. /// 通知值变化
  172. delegate?.IBNumberEditText(textField: numberField)
  173. }
  174. }
  175. extension IBNumberEditText: UITextFieldDelegate {
  176. func textFieldDidBeginEditing(_ textField: UITextField) {
  177. if Double(textField.text!) == 0 {
  178. textField.text = ""
  179. }
  180. }
  181. func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
  182. /// 解决删除按钮失效问题
  183. if (range.length == 1 && string.count == 0) {
  184. return true
  185. }
  186. if let decimalPlace = decimalPlace,
  187. let num = textField.text?.split(separator: ".").compactMap(String.init),
  188. num.count == 2, num[1].count == decimalPlace {
  189. return false
  190. }
  191. return true
  192. }
  193. func textFieldDidEndEditing(_ textField: UITextField) {
  194. /// 类型为整数型
  195. if valueType == 1 {
  196. self.currentIntNumbers = Int(self.currentIntNumbers/self.incrementIntNum)*Int(self.incrementIntNum)
  197. }
  198. /// numberInputViewDidEndEditing
  199. delegate?.numberInputViewDidEndEditing(self)
  200. }
  201. }
  202. protocol IBNumberEditTextDelegate: class {
  203. /// valueChanged 触发
  204. ///
  205. /// - Parameter textField: 值变化的输入框
  206. func IBNumberEditText(textField: UITextField)
  207. /// 按钮点击出发
  208. ///
  209. /// - Parameters:
  210. /// - buttonType: 按钮类型
  211. func numberInputView(_ numberInputView: IBNumberEditText, _ buttonType: NumberInputViewButtonType)
  212. /// numberInputViewDidEndEditing
  213. /// - Parameter numberInputView: numberInputView
  214. func numberInputViewDidEndEditing(_ numberInputView: IBNumberEditText)
  215. }