// // IBNumberEditText.swift // MTP2_iOS // // Created by Handy_Cao on 2018/11/10. // Copyright © 2018 Muchinfo. All rights reserved. // import UIKit /// 输入框按钮类型 /// /// - Add: 加 /// - Subtract: 减 enum NumberInputViewButtonType { case Add case Subtract } @IBDesignable class IBNumberEditText: UIView { // MARK: - 属性列表 /// 减号 @IBOutlet weak var minusBtn: IBButton! /// 加号 @IBOutlet weak var addBtn: IBButton! /// 输入框 @IBOutlet weak var numberField: IBTextField! /// 定义container为DemoView的子view, 以便更方便的封装xib @IBOutlet weak var containerView: UIView! /// 小数位,如果需要则设置 var decimalPlace: Int? /// 增量(默认值为1) var incrementIntNum = 1 var incrementDoubleNum: Double = 1 /// 最大值 var maxIntNum = Int.max var maxDoubleNum = Double(Int.max) /// 最小值 var minIntNum = 0 var minDoubleNum = 0.0 /// 是否循环 var isWarp = false /// 不允许交互 override var isUserInteractionEnabled: Bool { didSet { addBtn.layer.borderColor = UIColorFromHex(rgbValue: isUserInteractionEnabled ? 0x333333 : 0xcccccc).cgColor minusBtn.layer.borderColor = UIColorFromHex(rgbValue: isUserInteractionEnabled ? 0x333333 : 0xcccccc).cgColor numberField.textColor = UIColorFromHex(rgbValue: isUserInteractionEnabled ? 0x3384F3 : 0x999999) } } /// 代理 weak var delegate: IBNumberEditTextDelegate? /// 需要的值类型 1: Int 2: Double var valueType = 1 { didSet { switch valueType { case 1: numberField.keyboardType = .numberPad default: numberField.keyboardType = .decimalPad } } } /// 当前Int值 var currentIntNumbers: Int { get { return Int(numberField.text!) ?? 0 } set { if newValue > maxIntNum { numberField.text = String(maxIntNum) } else { numberField.text = String(newValue) } delegate?.IBNumberEditText(textField: numberField) } } /// 当前Double值 var currentDoubleNumbers: Double { get { if let decimalPlace = decimalPlace { /// FIXME: - 暂时用于解决浮点数计算失真问题 return Double(String(format: "%.\(decimalPlace)f", Double(numberField.text!) ?? 0)) ?? 0 } else { return Double(numberField.text!) ?? 0 } } set { if let decimalPlace = decimalPlace { if Double(Int(newValue)) == newValue { numberField.text = newValue.toString(reserve: decimalPlace) } else { numberField.text = String(format: "%.\(decimalPlace)f", newValue) } } else { if Double(Int(newValue)) == newValue { numberField.text = newValue.toString(reserve: decimalPlace ?? 0) } else { numberField.text = newValue.toString(reserve: decimalPlace ?? 0) } } delegate?.IBNumberEditText(textField: numberField) } } // MARK: - 生命周期 override init(frame: CGRect) { super.init(frame: frame) initViewFromNib() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) initViewFromNib() } private func initViewFromNib() { /// 需要这句代码,不能直接写UINib(nibName: "MyView", bundle: nil),不然不能在storyboard中显示 let bundle = Bundle.init(for: self.classForCoder) let nib = UINib(nibName: "NumberEditText", bundle: bundle) containerView = nib.instantiate(withOwner: self, options: nil)[0] as? UIView containerView.frame = bounds addSubview(containerView) } override func awakeFromNib() { NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextField.textDidChangeNotification, object: numberField) } @objc fileprivate func valueChanged() { delegate?.IBNumberEditText(textField: numberField) } deinit { NotificationCenter.default.removeObserver(self) } // MARK: - 交互相关 @IBAction func onButtonPressed(_ sender: IBButton) { switch sender { case addBtn: if valueType == 1 { if currentIntNumbers < maxIntNum { currentIntNumbers += incrementIntNum } else if isWarp { currentIntNumbers = minIntNum } } else { if currentDoubleNumbers < maxDoubleNum { currentDoubleNumbers += incrementDoubleNum } else if isWarp { currentDoubleNumbers = minDoubleNum } } /// 出发代理 guard let delegate = self.delegate else { return } delegate.numberInputView(self, .Add) case minusBtn: if valueType == 1 { if currentIntNumbers > minIntNum { currentIntNumbers -= incrementIntNum } else if isWarp { currentIntNumbers = maxIntNum } } else { if currentDoubleNumbers > minDoubleNum { currentDoubleNumbers -= incrementDoubleNum } else if isWarp { currentDoubleNumbers = maxDoubleNum } } /// 出发代理 guard let delegate = self.delegate else { return } delegate.numberInputView(self, .Subtract) default: break } /// 通知值变化 delegate?.IBNumberEditText(textField: numberField) } /// 是否置为不可用 var isDisabled = false { didSet { self.isUserInteractionEnabled = !isDisabled addBtn.isEnabled = !isDisabled minusBtn.isEnabled = !isDisabled } } } extension IBNumberEditText: UITextFieldDelegate { func textFieldDidBeginEditing(_ textField: UITextField) { if Double(textField.text!) == 0 { textField.text = "" } } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { /// 解决删除按钮失效问题 if (range.length == 1 && string.count == 0) { return true } if let decimalPlace = decimalPlace, let num = textField.text?.split(separator: ".").compactMap(String.init), num.count == 2, num[1].count == decimalPlace { return false } return true } func textFieldDidEndEditing(_ textField: UITextField) { /// 类型为整数型 if valueType == 1 { self.currentIntNumbers = Int(self.currentIntNumbers/self.incrementIntNum)*Int(self.incrementIntNum) } /// numberInputViewDidEndEditing delegate?.numberInputViewDidEndEditing(self) } } protocol IBNumberEditTextDelegate: class { /// valueChanged 触发 /// /// - Parameter textField: 值变化的输入框 func IBNumberEditText(textField: UITextField) /// 按钮点击出发 /// /// - Parameters: /// - buttonType: 按钮类型 func numberInputView(_ numberInputView: IBNumberEditText, _ buttonType: NumberInputViewButtonType) /// numberInputViewDidEndEditing /// - Parameter numberInputView: numberInputView func numberInputViewDidEndEditing(_ numberInputView: IBNumberEditText) }