MCDatePikerView.swift 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. //
  2. // MCDatePikerView.swift
  3. // HCQuanfangtong
  4. //
  5. // Created by Apple on 2022/5/5.
  6. // Copyright © 2022 Jyp. All rights reserved.
  7. //
  8. import UIKit
  9. import SwiftDate
  10. import RxSwift
  11. @objc
  12. enum MCDatePikerViewTypeForObject_c : Int{
  13. case yyyyMM = 0
  14. case yyyyMMdd
  15. case HHmm
  16. case HHmmss
  17. case yyyyMMddHHmm
  18. case yyyyMMddHHmmss
  19. }
  20. /// Date PikerView
  21. /// 年月
  22. /// 年月日
  23. /// 时分
  24. /// 时分秒
  25. /// 年月日时分
  26. /// 年月日时分秒
  27. @objcMembers class MCDatePikerView: UIView, MCPopBeAssociatedDelegate{
  28. /// 选中的日期
  29. var selectBlock : ((_ date: Date?)->Void)?
  30. var selectDateStrBlock: ((_ dateStr: String?)->Void)?
  31. convenience init (default defaultDate: Date = Date.init(), min minDate: Date? = nil, max maxDate: Date? = nil){
  32. self.init(type: .yyyyMMdd, default: defaultDate, min: minDate, max: maxDate)
  33. }
  34. /// 字符串初始化方法 类型为yyyy-MM-dd
  35. /// - Parameters:
  36. /// - defaultDateStr: <#defaultDateStr description#>
  37. /// - minDateStr: <#minDateStr description#>
  38. /// - maxDateStr: <#maxDateStr description#>
  39. /// - selectDateStrBlock: <#selectDateStrBlock description#>
  40. convenience init (defaultDateStr: String?, minDateStr: String?, maxDateStr: String?, selectDateStrBlock: ((_ dateStr: String?)->Void)?){
  41. self.init(ocType: .yyyyMMdd, defaultDateStr: defaultDateStr, minDateStr: minDateStr, maxDateStr: maxDateStr, selectDateStrBlock: selectDateStrBlock)
  42. }
  43. /// 字符串初始化方法 类型为yyyy-MM-dd
  44. /// - Parameters:
  45. /// - ocType: 类型
  46. /// - defaultDateStr: <#defaultDateStr description#>
  47. /// - minDateStr: <#minDateStr description#>
  48. /// - maxDateStr: <#maxDateStr description#>
  49. /// - selectDateStrBlock: <#selectDateStrBlock description#>
  50. convenience init (ocType: MCDatePikerViewTypeForObject_c, defaultDateStr: String?, minDateStr: String?, maxDateStr: String?, selectDateStrBlock: ((_ dateStr: String?)->Void)?){
  51. var defaultDate: Date = Date.init()
  52. var minDate: Date?
  53. var maxDate: Date?
  54. if !defaultDateStr.isEmptyStr {
  55. defaultDate = Date.init(defaultDateStr!) ?? Date.init()
  56. }
  57. if !minDateStr.isEmptyStr{
  58. minDate = Date.init(minDateStr!)
  59. }
  60. if !maxDateStr.isEmptyStr{
  61. maxDate = Date.init(maxDateStr!)
  62. }
  63. self.init(ocType: ocType, default: defaultDate, min: minDate, max: maxDate)
  64. self.selectDateStrBlock = selectDateStrBlock
  65. }
  66. convenience init (ocType: MCDatePikerViewTypeForObject_c, default defaultDate: Date = Date.init(), min minDate: Date? = nil, max maxDate: Date? = nil){
  67. let dateType : MCDatePikerView.DateType
  68. switch ocType {
  69. case .yyyyMM:
  70. dateType = .yyyyMM
  71. case .yyyyMMdd:
  72. dateType = .yyyyMMdd
  73. case .HHmm:
  74. dateType = .HHmm
  75. case .HHmmss:
  76. dateType = .HHmmss
  77. case .yyyyMMddHHmm:
  78. dateType = .yyyyMMddHHmm
  79. case .yyyyMMddHHmmss:
  80. dateType = .yyyyMMddHHmmss
  81. }
  82. self.init(type: dateType, default: defaultDate, min: minDate, max: maxDate)
  83. }
  84. init(type dateType: MCDatePikerView.DateType, default defaultDate: Date = Date.init(), min minDate: Date? = nil, max maxDate: Date? = nil) {
  85. self.defaultDate = defaultDate
  86. super.init(frame: CGRect.zero)
  87. self.type = dateType
  88. self.minDate = minDate
  89. self.maxDate = maxDate
  90. if let minDate = minDate {
  91. if self.defaultDate < minDate{
  92. self.defaultDate = minDate
  93. }
  94. }
  95. if let maxDate = maxDate {
  96. if self.defaultDate > maxDate{
  97. self.defaultDate = maxDate
  98. }
  99. }
  100. if dateType != .HHmm && dateType != .HHmmss{
  101. self.delegate = MCDatePikerDelegateImp_yyyyMM.init()
  102. }
  103. else {
  104. self.delegate = MCDatePikerDelegateImp_HHmm.init()
  105. }
  106. self.delegate?.defaultDate = self.defaultDate
  107. self.delegate?.maxDate = self.maxDate
  108. self.delegate?.minDate = self.minDate
  109. self.delegate?.style = self
  110. self.createUI()
  111. self.resetPikerViewCurrentDate()
  112. }
  113. enum DateType:String{
  114. case yyyyMM = "yyyy-MM"
  115. case yyyyMMdd = "yyyy-MM-dd"
  116. case HHmm = "HH:mm"
  117. case HHmmss = "HH:mm:ss"
  118. case yyyyMMddHHmm = "yyyy-MM-dd HH:mm"
  119. case yyyyMMddHHmmss = "yyyy-MM-dd HH:mm:ss"
  120. }
  121. var dateType: MCDatePikerView.DateType{
  122. self.type
  123. }
  124. //MARK: - Private Property
  125. /// 最小
  126. private var minDate : Date?
  127. /// 最大
  128. private var maxDate : Date?
  129. /// 默认日期
  130. private var defaultDate : Date
  131. /// <#Description#>
  132. lazy private var pikerView : UIPickerView! = {
  133. let pikerView = UIPickerView.init(frame: CGRect.zero)
  134. pikerView.delegate = self.delegate
  135. pikerView.dataSource = self.delegate
  136. pikerView.backgroundColor = self.delegateForPikerBackgroundColor()
  137. return pikerView
  138. }()
  139. private var type : MCDatePikerView.DateType = .yyyyMM
  140. private var delegate : MCDatePikerDelegate!
  141. //MARK: - MCPopBeAssociatedDelegate
  142. /// 是否显示
  143. var isShow: Bool! = false
  144. /// 信号 : show or hidden
  145. var binderIsShow: PublishSubject<Bool>! = PublishSubject.init()
  146. /// 信号 : 选中了字符串
  147. var binderValue: PublishSubject<MCPopSelectedModel?>? = PublishSubject.init()
  148. var binderValues: PublishSubject<[MCPopSelectedModel]?>? = PublishSubject.init()
  149. @discardableResult
  150. func show() -> Self{
  151. self.isShow = true
  152. self.binderIsShow.onNext(true)
  153. let window = kAppDelegateWindow
  154. window.addSubview(self)
  155. self.mas_makeConstraints { make in
  156. make?.edges.mas_equalTo()(window)
  157. }
  158. return self
  159. }
  160. func hidden(){
  161. self.isShow = false
  162. self.binderIsShow.onNext(false)
  163. self.removeFromSuperview()
  164. }
  165. func sendSingle(with str: String) {
  166. let date = str.toDate()
  167. if let date = date{
  168. //处理pikerview选择
  169. self.defaultDate = date.date
  170. self.delegate?.defaultDate = self.defaultDate
  171. self.resetPikerViewCurrentDate()
  172. var dataSources: [MCPopSelectedModel] = []
  173. switch self.dateType {
  174. case .yyyyMM:
  175. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.year), index: nil))
  176. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.month), index: nil))
  177. case .yyyyMMdd:
  178. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.year), index: nil))
  179. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.month), index: nil))
  180. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.day), index: nil))
  181. case .yyyyMMddHHmm:
  182. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.year), index: nil))
  183. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.month), index: nil))
  184. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.day), index: nil))
  185. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.hour), index: nil))
  186. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.minute), index: nil))
  187. case .yyyyMMddHHmmss:
  188. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.year), index: nil))
  189. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.month), index: nil))
  190. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.day), index: nil))
  191. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.hour), index: nil))
  192. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.minute), index: nil))
  193. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.second), index: nil))
  194. case .HHmm:
  195. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.hour), index: nil))
  196. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.minute), index: nil))
  197. case .HHmmss:
  198. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.hour), index: nil))
  199. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.minute), index: nil))
  200. dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.second), index: nil))
  201. }
  202. self.binderValue?.onNext(MCPopSelectedModel.init(name: date.toFormat(self.getDateFormatter()), index: nil))
  203. self.binderValues?.onNext(dataSources)
  204. }
  205. else{
  206. self.binderValue?.onNext(nil)
  207. self.binderValues?.onNext(nil)
  208. }
  209. }
  210. /// 设置数据源 不可操作
  211. /// - Parameter sources: <#sources description#>
  212. func setDataSource<T>(with sources: T) -> Bool {
  213. return false
  214. }
  215. /// 获取数据源
  216. /// - Returns: <#description#>
  217. func getDataSource() -> Any?{
  218. return []
  219. }
  220. //MARK: -
  221. required init?(coder: NSCoder) {
  222. fatalError("init(coder:) has not been implemented")
  223. }
  224. deinit{
  225. DLog("\(self) dealloc")
  226. }
  227. }
  228. extension MCDatePikerView{
  229. private func createUI(){
  230. //背景view
  231. let backgroundView = UIControl.init(frame: CGRect.zero)
  232. backgroundView.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 0.3)
  233. self.addSubview(backgroundView)
  234. backgroundView.mas_makeConstraints { make in
  235. make?.edges.mas_equalTo()(self)
  236. }
  237. _ = backgroundView.rx.controlEvent(.touchUpInside).takeUntil(self.rx.deallocated).subscribe(onNext:{[unowned self] in
  238. self.hidden()
  239. })
  240. let contentView = UIView.init(frame: CGRect.zero)
  241. contentView.isUserInteractionEnabled = true
  242. contentView.backgroundColor = self.delegateForPikerBackgroundColor()
  243. self.addSubview(contentView)
  244. contentView.mas_makeConstraints { make in
  245. make?.left.right().bottom().mas_equalTo()(self)
  246. }
  247. contentView.addSubview(pikerView)
  248. pikerView.mas_makeConstraints { make in
  249. make?.left.right().mas_equalTo()(contentView)
  250. make?.height.offset()(self.delegateForPikerHeight())
  251. make?.bottom.mas_equalTo()(contentView)?.offset()(-self.delegateForPikerViewBottomSpace())
  252. }
  253. let toolBar = UIView.init(frame: CGRect.zero)
  254. toolBar.backgroundColor = self.delegateForToolBarBackgroundColor()
  255. contentView.addSubview(toolBar)
  256. toolBar.mas_makeConstraints { make in
  257. make?.left.right().mas_equalTo()(contentView)
  258. make?.height.offset()(self.delegateForToolBarHeight())
  259. make?.bottom.mas_equalTo()(self.pikerView.mas_top)
  260. make?.top.mas_equalTo()(contentView)
  261. }
  262. let cancelBtn = UIButton.init(type: UIButton.ButtonType.custom)
  263. cancelBtn.setTitle(self.delegateForCancelTitle(), for: .normal)
  264. cancelBtn.setTitleColor(self.delegateForCancelTitleColor(), for: .normal)
  265. cancelBtn.titleLabel?.font = self.delegateForCancelTitleFont()
  266. cancelBtn.backgroundColor = self.delegateForCancelBackgroundColor()
  267. toolBar.addSubview(cancelBtn)
  268. cancelBtn.mas_makeConstraints { make in
  269. make?.left.mas_equalTo()(toolBar)?.offset()(self.delegateForToolBarItemMarginLeftSpace())
  270. make?.top.mas_equalTo()(toolBar)?.offset()(self.delegateForToolBarItemMarginTopSpace())
  271. make?.bottom.mas_equalTo()(toolBar)?.offset()(-self.delegateForToolBarItemMarginTopSpace())
  272. make?.width.offset()(self.delegateForToolBarItemWidth())
  273. }
  274. _ = cancelBtn.rx.tap.takeUntil(self.rx.deallocated).subscribe(onNext:{[unowned self] in
  275. self.hidden()
  276. })
  277. let okBtn = UIButton.init(type: UIButton.ButtonType.custom)
  278. okBtn.setTitle(self.delegateForOKTitle(), for: .normal)
  279. okBtn.setTitleColor(self.delegateForOKTitleColor(), for: .normal)
  280. okBtn.titleLabel?.font = self.delegateForOKTitleFont()
  281. okBtn.backgroundColor = self.delegateForOKBackgroundColor()
  282. toolBar.addSubview(okBtn)
  283. okBtn.mas_makeConstraints { make in
  284. make?.right.mas_equalTo()(toolBar)?.offset()(-self.delegateForToolBarItemMarginLeftSpace())
  285. make?.top.mas_equalTo()(toolBar)?.offset()(self.delegateForToolBarItemMarginTopSpace())
  286. make?.bottom.mas_equalTo()(toolBar)?.offset()(-self.delegateForToolBarItemMarginTopSpace())
  287. make?.width.offset()(self.delegateForToolBarItemWidth())
  288. }
  289. _ = okBtn.rx.tap.takeUntil(self.rx.deallocated).subscribe(onNext:{[unowned self] in
  290. let date = self.delegate.finallyDate
  291. let dateStr = date.toFormat(self.getDateFormatter())
  292. self.sendSingle(with: dateStr)
  293. self.selectBlock?(date)
  294. self.selectDateStrBlock?(dateStr)
  295. self.hidden()
  296. })
  297. }
  298. /// pikerView 设置当前选中的时间
  299. private func resetPikerViewCurrentDate(){
  300. self.pikerView?.reloadAllComponents()
  301. if self.dateType != .HHmm && self.dateType != .HHmmss{
  302. self.pikerView?.selectRow(self.defaultDate.year - 1, inComponent: 0, animated: false)
  303. self.pikerView?.selectRow(self.delegate.getAdjustMonth(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 1) / 2, targetMonth: self.delegate.month), inComponent: 1, animated: false)
  304. let components = self.delegate.numberOfComponents(in: self.pikerView)
  305. if components > 2{
  306. self.pikerView?.selectRow(self.delegate.getAdjusetDay(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 2) / 2, beforeDay: nil, targetDay: self.delegate.day), inComponent: 2, animated: false)
  307. }
  308. if components > 3{
  309. self.pikerView?.selectRow(self.delegate.getAdjustHour(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 3) / 2, targetHour: self.delegate.hour), inComponent: 3, animated: false)
  310. }
  311. if components > 4{
  312. self.pikerView?.selectRow(self.delegate.getAdjustMinute(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 4) / 2, targetMinute: self.delegate.minute), inComponent: 4, animated: false)
  313. }
  314. if components > 5{
  315. self.pikerView?.selectRow(self.delegate.getAdjustSeconds(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 5) / 2, targetSeconds: self.delegate.seconds), inComponent: 5, animated: false)
  316. }
  317. }
  318. else{
  319. self.pikerView?.selectRow(self.delegate.getAdjustHour(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 0) / 2, targetHour: self.delegate.hour), inComponent: 0, animated: false)
  320. self.pikerView?.selectRow(self.delegate.getAdjustMinute(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 1) / 2, targetMinute: self.delegate.minute), inComponent: 1, animated: false)
  321. if self.delegate.numberOfComponents(in: self.pikerView) > 2{
  322. self.pikerView?.selectRow(self.delegate.getAdjustSeconds(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 2) / 2, targetSeconds: self.delegate.seconds), inComponent: 2, animated: false)
  323. }
  324. }
  325. }
  326. private func getDateFormatter() -> String{
  327. var dateFormatter : String
  328. switch self.dateType {
  329. case .yyyyMM:
  330. dateFormatter = "yyyy-MM"
  331. case .yyyyMMdd:
  332. dateFormatter = "yyyy-MM-dd"
  333. case .yyyyMMddHHmm:
  334. dateFormatter = "yyyy-MM-dd HH:mm"
  335. case .yyyyMMddHHmmss:
  336. dateFormatter = "yyyy-MM-dd HH:mm:ss"
  337. case .HHmm:
  338. dateFormatter = "HH:mm"
  339. case .HHmmss:
  340. dateFormatter = "HH:mm:ss"
  341. }
  342. return dateFormatter
  343. }
  344. @objc(setSwiftDateRegion)
  345. public class func setSwiftDateRegion(){
  346. SwiftDate.defaultRegion = .local
  347. }
  348. }