123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- //
- // MCProxyTextFieldRx.swift
- // HCQuanfangtong
- //
- // Created by Apple on 2022/4/7.
- // Copyright © 2022 Jyp. All rights reserved.
- //
- import Foundation
- import RxSwift
- import RxCocoa
- import UIKit
- enum KeybordInputType : NSInteger{
- case number = 0 //数字 整数位 【最大输入长度】
- case decimal //数字强校验 不能0开头 ,可以输入小数 [整数位长度,小数位长度,最大值可以为空]
- case charater //文本 (不可以输入中文) [最大输入长度]
- case text //可以输入任何东西 【最大输入长度】
- case degital //数字强校验 不能0开头 整数 [最大输入长度,最大值可以为空]
- case phone //电话号码
- case numberOrLetter //数字或26个字母 【最大输入长度】
- case chinese //只可以输入中文
- }
- //自动注入
- @propertyWrapper class TextFieldWrapper{
-
- /// 输入类型
- var type : KeybordInputType
-
- /// 最大长度
- var maxLength : Int?
-
- /// 最大值
- var maxValue : Float?
-
- /// 小数位
- var decimalLength : Int?
-
- /// 检验的block
- var checkBlock : (()->Bool)?
-
- /// 结束输入
- var endBlock : (()->Void)
- var defaultValue : UITextField?
-
- /// 是否可以输入负数
- var limitNagativeNumber : Bool
-
- let disposeAutoRelease = DisposeBag()
- var wrappedValue : UITextField?{
- didSet{
- wrappedValue?.rx.bindDelegate(delegate: MCTextFieldDelegate.init(type: type, maxLength: maxLength, maxValue: maxValue, decimalLength: decimalLength, limitNagativeNumber: limitNagativeNumber, checkBlock: checkBlock, endBlock: endBlock)).subscribe().disposed(by: disposeAutoRelease)
- }
- }
-
- init(wrappedValue defaultValue: UITextField? = nil, type:KeybordInputType = .decimal, maxLength: Int? = nil, decimalLength: Int? = nil, maxValue: Float? = nil, limitNagativeNumber: Bool = true, checkBlock: (()->Bool)? = nil, endBlock: @escaping (()->Void)){
- self.defaultValue = defaultValue
- self.maxLength = maxLength
- self.maxValue = maxValue
- self.decimalLength = decimalLength
- self.endBlock = endBlock
- self.type = type
- self.limitNagativeNumber = limitNagativeNumber
- }
-
- }
- @propertyWrapper class TextFieldPhoneWrapper : TextFieldWrapper{
- override var wrappedValue : UITextField?{
- didSet{
- if wrappedValue.isNotNil{
- wrappedValue?.rx.bindDelegate(delegate: MCTextFieldDelegate.init(type: type, maxLength: maxLength, maxValue: maxValue, decimalLength: decimalLength, limitNagativeNumber: limitNagativeNumber, checkBlock: checkBlock, endBlock: endBlock)).subscribe().disposed(by: disposeAutoRelease)
- }
- }
- }
-
- init(wrappedValue defaultValue: UITextField? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)){
- super.init(wrappedValue: defaultValue, type: .phone, maxLength: nil, decimalLength: nil, maxValue: nil, limitNagativeNumber: true, checkBlock: checkBlock, endBlock: block)
- }
- }
- @propertyWrapper class TextFieldDecimalWrapper : TextFieldWrapper{
- override var wrappedValue : UITextField?{
- didSet{
- if wrappedValue.isNotNil{
- wrappedValue?.rx.bindDelegate(delegate: MCTextFieldDelegate.init(type: type, maxLength: maxLength, maxValue: maxValue, decimalLength: decimalLength, limitNagativeNumber: limitNagativeNumber, checkBlock: checkBlock, endBlock: endBlock)).subscribe().disposed(by: disposeAutoRelease)
- }
- }
- }
-
- init(wrappedValue defaultValue: UITextField? = nil, maxValue: Float? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)){
- super.init(wrappedValue: defaultValue, type: .decimal, maxLength: 9, decimalLength: 2, maxValue: maxValue, limitNagativeNumber: true, checkBlock: checkBlock, endBlock: block)
- }
-
- }
- @propertyWrapper class TextFieldDegitalWrapper : TextFieldWrapper{
- override var wrappedValue : UITextField?{
- didSet{
- if wrappedValue.isNotNil{
- wrappedValue?.rx.bindDelegate(delegate: MCTextFieldDelegate.init(type: type, maxLength: maxLength, maxValue: maxValue, decimalLength: decimalLength, limitNagativeNumber: limitNagativeNumber, checkBlock: checkBlock, endBlock: endBlock)).subscribe().disposed(by: disposeAutoRelease)
- }
- }
- }
-
- init(wrappedValue defaultValue: UITextField? = nil, maxLength: Int? = nil, maxValue: Float? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)){
- super.init(wrappedValue: defaultValue, type: .decimal, maxLength: maxLength, decimalLength: nil, maxValue: maxValue, limitNagativeNumber: true, checkBlock: checkBlock, endBlock: block)
- }
- }
- @propertyWrapper class TextFieldOtherWrapper : TextFieldWrapper{
- override var wrappedValue : UITextField?{
- didSet{
- if wrappedValue.isNotNil{
- if self.type == .chinese || self.type == .text{
- wrappedValue!.bindChineseDelegate(delegate: MCTextFieldDelegate.chinese(maxLength: maxLength, block: endBlock))
- return
- }
- wrappedValue?.rx.bindDelegate(delegate: MCTextFieldDelegate.init(type: type, maxLength: maxLength, maxValue: maxValue, decimalLength: decimalLength, limitNagativeNumber: limitNagativeNumber, checkBlock: checkBlock, endBlock: endBlock)).subscribe().disposed(by: disposeAutoRelease)
- }
- }
- }
-
- init(wrappedValue defaultValue: UITextField? = nil, type: KeybordInputType, maxLength: Int? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)){
- super.init(wrappedValue: defaultValue, type: type, maxLength: maxLength, decimalLength: nil, maxValue: nil, limitNagativeNumber: true, checkBlock: checkBlock, endBlock: block)
- }
-
- }
- class MCTextFieldDelegate : NSObject, UITextFieldDelegate{
-
- /// 输入类型
- var type : KeybordInputType
-
- /// 最大长度
- var maxLength : Int?
-
- /// 最大值
- var maxValue : Float?
-
- /// 小数位数
- var decimalLength : Int?
-
- /// 是否限制输入负数
- var limitNagativeNumber : Bool!
-
- /// 检验的block
- var checkBlock : (()->Bool)?
-
- /// 输入结束
- var endBlock : (()->Void)
-
-
-
- init(type:KeybordInputType = .decimal, maxLength: Int? = nil, maxValue: Float? = nil, decimalLength: Int? = nil, limitNagativeNumber: Bool = true, checkBlock: (()->Bool)? = nil, endBlock: @escaping (()->Void)){
- self.maxLength = maxLength
- self.maxValue = maxValue
- self.decimalLength = decimalLength
- self.endBlock = endBlock
- self.checkBlock = checkBlock
- self.type = type
- self.limitNagativeNumber = limitNagativeNumber
- }
-
-
-
-
-
- public static func decimalDefault(maxValue: Float? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)) -> MCTextFieldDelegate{
- MCTextFieldDelegate.init(type: .decimal, maxLength: 9, maxValue: maxValue, decimalLength: 2, limitNagativeNumber: true, checkBlock: checkBlock, endBlock: block)
- }
-
- public static func phone(checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)) -> MCTextFieldDelegate{
- MCTextFieldDelegate.init(type: .phone, checkBlock: checkBlock, endBlock: block)
- }
-
- public static func text(maxLength: Int? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)) -> MCTextFieldDelegate{
- MCTextFieldDelegate.init(type: .text, maxLength: maxLength, checkBlock: checkBlock, endBlock: block)
- }
-
- public static func charater(maxLength: Int? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)) -> MCTextFieldDelegate{
- MCTextFieldDelegate.init(type: .charater, maxLength: maxLength, checkBlock: checkBlock, endBlock: block)
- }
-
- public static func degital(maxLength: Int? = nil, maxValue: Float? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)) -> MCTextFieldDelegate{
- MCTextFieldDelegate.init(type: .degital, maxLength: maxLength, maxValue: maxValue, checkBlock: checkBlock, endBlock: block)
- }
-
- public static func number(maxLength: Int? = nil, maxValue: Float? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)) -> MCTextFieldDelegate{
- MCTextFieldDelegate.init(type: .number, maxLength: maxLength, maxValue: maxValue, checkBlock: checkBlock, endBlock: block)
- }
-
- public static func numberOrLetter(maxLength: Int? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)) -> MCTextFieldDelegate{
- MCTextFieldDelegate.init(type: .numberOrLetter, maxLength: maxLength, checkBlock: checkBlock, endBlock: block)
- }
-
- public static func chinese(maxLength: Int? = nil, checkBlock: (()->Bool)? = nil, block: @escaping (()->Void)) -> MCTextFieldDelegate{
- MCTextFieldDelegate.init(type: .chinese, maxLength: maxLength, checkBlock: checkBlock, endBlock: block)
- }
-
- var regex : String{
- get{
- if type == .decimal{
- if maxLength.isNil || decimalLength.isNil{
- fatalError("配置有问题")
- }
- return self.limitNagativeNumber ? "(([0]|(0[.]\\d{0,\(decimalLength!)}))|([1-9]\\d{0,\(maxLength! - 1)}(([.]\\d{0,\(decimalLength!)})?)))?" : "(\\-)?(([0]|(0[.]\\d{0,\(decimalLength!)}))|([1-9]\\d{0,\(maxLength! - 1)}(([.]\\d{0,\(decimalLength!)})?)))?"
- }
- if type == .degital{
- //纯数字 强效验以0开头
- if maxLength.isNotNil{
- return self.limitNagativeNumber ? "([1-9]\\d{0,\(maxLength! - 1)})?" : "(\\-)?([1-9]\\d{0,\(maxLength! - 1)})?"
- }
- else{
- return self.limitNagativeNumber ? "([1-9][0-9]*)?" : "(\\-)?([1-9][0-9]*)?"
- }
- }
- if type == .number{
- return maxLength.isNotNil ? "(\\d{0,\(maxLength!)})?" : "([0-9]*)?"
- }
- if type == .phone{
- return "([1]\\d{0,10})?"
- }
- if type == .text{
- // return maxLength.isNotNil ? "([\\S\\s]{0,\(maxLength!)})?" : "([\\S\\s]*)?"
- return "([\\S\\s]*)?"
- }
- if type == .charater{
- return maxLength.isNotNil ? "([^\\u4e00-\\u9fa5]{0,\(maxLength!)})?" : "([^\\u4e00-\\u9fa5]*)?"
- }
- if type == .numberOrLetter{
- return maxLength.isNotNil ? "([\\w]{0,\(maxLength!)})?" : "([\\w]*)?"
- }
- if type == .chinese{
- // return maxLength.isNotNil ? "([\\u4e00-\\u9fa5]{0,\(maxLength!)})?" : "([\\u4e00-\\u9fa5]*)?"
- return "([\\u4e00-\\u9fa5]*)?"
- }
- return ""
- }
- }
-
- func getRegexStr(_ text: String?) -> String?{
- if let text = text{
- do {
-
- let regularRxpression = try NSRegularExpression.init(pattern: self.regex, options: .caseInsensitive)
- let result = regularRxpression.matches(in: text, range: NSMakeRange(0, text.count))
- var resultArray : [String] = []
- var resultStr: String?
- switch self.type {
- case .number, .text, .charater, .numberOrLetter, .chinese:
- for item in result{
- resultArray.append(NSString.init(format: "%@", text).substring(with: item.range))
- }
- resultStr = resultArray.joined(separator: "")
- if self.maxLength.isNotNil{
- if (resultStr?.count ?? 0) > self.maxLength! && self.maxLength! > 0{
- resultStr = NSString.init(string: resultStr!).substring(with: NSRange.init(location: 0, length: self.maxLength!))
- }
- }
-
- if self.type == .number{
- if self.maxValue.isNotNil{
- if Convert.toString(resultStr, decimalNumber: 0) > self.maxValue!{
- resultStr = Convert.toString(self.maxValue, decimalNumber: 0)
- }
- }
- resultStr = Convert.toString(resultStr, decimalNumber: 0)
- }
-
-
- case .decimal, .degital:
- for item in result{
- resultArray.append(NSString.init(format: "%@", text).substring(with: item.range))
- break
- }
- resultStr = resultArray.joined(separator: "")
- if self.maxValue.isNotNil{
- if Convert.toString(resultStr, decimalNumber: self.type == .decimal ? self.decimalLength:0) > self.maxValue!{
- resultStr = Convert.toString(self.maxValue, decimalNumber: self.type == .decimal ? self.decimalLength:0)
- }
- }
- resultStr = Convert.toString(resultStr, decimalNumber: self.type == .decimal ? self.decimalLength:0)
- case .phone:
- for item in result{
- resultArray.append(NSString.init(format: "%@", text).substring(with: item.range))
- }
- resultStr = resultArray.joined(separator: "")
- if (resultStr?.count ?? 0) > 11{
- resultStr = NSString.init(string: resultStr!).substring(with: NSRange.init(location: 0, length: 11))
- }
-
- }
- return resultStr
- } catch _ {
- return nil
- }
- }
- return nil
- }
-
-
- func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
- let toString : String? = (textField.text as NSString?)?.replacingCharacters(in: range, with: string)
-
- if self.type == .text || self.type == .chinese{
- return true
- }
-
- if toString?.count ?? 0 > 0{
- let pricePredicate = NSPredicate.init(format: "SELF MATCHES %@", regex)
-
-
- if !pricePredicate.evaluate(with: toString){
- return false
- }
- else{
- if self.maxValue.isNotNil && (type == .decimal || type == .degital || type == .number){
- if Convert.toString(toString, decimalNumber: decimalLength) > self.maxValue!{
- return false
- }
- }
-
-
- }
- }
- return true
- }
-
-
- func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
- if self.checkBlock.isNil{
- return true
- }
- return self.checkBlock!()
- }
-
-
- func textFieldDidEndEditing(_ textField: UITextField) {
-
- if self.maxValue.isNotNil && (type == .decimal || type == .degital || type == .number){
- if Convert.toString(textField.text, decimalNumber: decimalLength) > self.maxValue!{
- textField.text = Convert.toString(self.maxValue, decimalNumber: decimalLength)
- }
- }
-
- if type == .decimal{
- textField.text = Convert.toString(textField.text, decimalNumber: decimalLength)
- // if textField.text.isEmptyStr{
- // textField.text = Convert.toString(0, decimalNumber: decimalLength)
- // }
- }
- else if type == .degital || type == .number{
- textField.text = Convert.toString(textField.text, decimalNumber: 0)
- }
- else{
- textField.text = textField.text
- }
-
- self.endBlock()
- }
-
- }
- extension UITextField{
- private struct AssociatedDelegateKey{
- static var delegate = "AssociatedDelegateKeyObservables"
- }
-
- private var associatedDelegate : MCTextFieldDelegate?{
- set{
- objc_setAssociatedObject(self, &AssociatedDelegateKey.delegate, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
- }
- get{
- objc_getAssociatedObject(self, &AssociatedDelegateKey.delegate) as? MCTextFieldDelegate
- }
- }
-
-
- func bindChineseDelegate(delegate: MCTextFieldDelegate){
- self.delegate = delegate
- self.associatedDelegate = delegate
- self.addTarget(self, action: #selector(mcDelegateConstraintTextFieldDidChange), for: UIControlEvents.editingChanged)
- }
-
-
- @objc func mcDelegateConstraintTextFieldDidChange(){
- guard let delegate = self.delegate as? MCTextFieldDelegate else{
- return
- }
-
- if delegate.type == .text || delegate.type == .chinese{
- let lang = self.textInputMode?.primaryLanguage
- if lang == "zh-Hans"{
- let textRange = self.markedTextRange
- if let range = textRange{
- if self.position(from: range.start, offset: 0) != nil{
- return
- }
- }
- }
-
- if let text = self.text{
- do {
- let regularRxpression = try NSRegularExpression.init(pattern: delegate.regex, options: .caseInsensitive)
- let result = regularRxpression.matches(in: text, range: NSMakeRange(0, text.count))
- var resultArray : [String] = []
- for item in result{
- resultArray.append(NSString.init(format: "%@", text).substring(with: item.range))
- }
- let resultStr = resultArray.joined(separator: "")
- if delegate.maxLength.isNotNil{
- if resultStr.count > (delegate.maxLength ?? 0){
- self.text = NSString.init(string: resultStr).substring(with: NSRange.init(location: 0, length: delegate.maxLength ?? 0))
- return
- }
- }
-
- if resultStr == self.text{
- return
- }
- self.text = resultStr
-
-
- } catch _ {
- }
-
- }
-
- }
-
-
- }
-
- }
- extension Reactive where Base:UITextField{
-
-
- var textDelegate : DelegateProxy<UITextField, UITextFieldDelegate>{
- return TextFieldDelegateProxy.proxy(for: base)
- }
-
- func bindDelegate(delegate:UITextFieldDelegate) ->RxSwift.Observable<[Any]>{
- self.base.delegate = delegate
- return textDelegate.methodInvoked(#selector(UITextFieldDelegate.textField(_:shouldChangeCharactersIn:replacementString:)))
- }
-
- var bindEndEditing : RxSwift.Observable<[Any]>{
- get{
- return textDelegate.methodInvoked(#selector(UITextFieldDelegate.textFieldDidEndEditing(_:)))
- }
- }
- var bindBeginEditing : RxSwift.Observable<[Any]>{
- get{
- return textDelegate.methodInvoked(#selector(UITextFieldDelegate.textFieldDidBeginEditing(_:)))
- }
- }
-
- }
- public class TextFieldDelegateProxy : DelegateProxy<UITextField, UITextFieldDelegate>,UITextFieldDelegate,DelegateProxyType{
-
-
- public static func currentDelegate(for object: UITextField) -> UITextFieldDelegate? {
- return object.delegate
- }
- public static func setCurrentDelegate(_ delegate: UITextFieldDelegate?, to object: UITextField) {
- object.delegate = delegate
- }
- public weak private(set) var textField : UITextField?
- init(textField : UITextField) {
- self.textField = textField
- super.init(parentObject: textField, delegateProxy: TextFieldDelegateProxy.self)
- }
- public static func registerKnownImplementations() {
- self.register {
- TextFieldDelegateProxy.init(textField: $0)
- }
- }
-
- public override func setForwardToDelegate(_ delegate: DelegateProxy<UITextField, UITextFieldDelegate>.Delegate?, retainDelegate: Bool) {
- super.setForwardToDelegate(delegate, retainDelegate: true)
- }
-
- }
|