// // MCDatePikerView.swift // HCQuanfangtong // // Created by Apple on 2022/5/5. // Copyright © 2022 Jyp. All rights reserved. // import UIKit import SwiftDate import RxSwift @objc enum MCDatePikerViewTypeForObject_c : Int{ case yyyyMM = 0 case yyyyMMdd case HHmm case HHmmss case yyyyMMddHHmm case yyyyMMddHHmmss } /// Date PikerView /// 年月 /// 年月日 /// 时分 /// 时分秒 /// 年月日时分 /// 年月日时分秒 @objcMembers class MCDatePikerView: UIView, MCPopBeAssociatedDelegate{ /// 选中的日期 var selectBlock : ((_ date: Date?)->Void)? var selectDateStrBlock: ((_ dateStr: String?)->Void)? convenience init (default defaultDate: Date = Date.init(), min minDate: Date? = nil, max maxDate: Date? = nil){ self.init(type: .yyyyMMdd, default: defaultDate, min: minDate, max: maxDate) } /// 字符串初始化方法 类型为yyyy-MM-dd /// - Parameters: /// - defaultDateStr: <#defaultDateStr description#> /// - minDateStr: <#minDateStr description#> /// - maxDateStr: <#maxDateStr description#> /// - selectDateStrBlock: <#selectDateStrBlock description#> convenience init (defaultDateStr: String?, minDateStr: String?, maxDateStr: String?, selectDateStrBlock: ((_ dateStr: String?)->Void)?){ self.init(ocType: .yyyyMMdd, defaultDateStr: defaultDateStr, minDateStr: minDateStr, maxDateStr: maxDateStr, selectDateStrBlock: selectDateStrBlock) } /// 字符串初始化方法 类型为yyyy-MM-dd /// - Parameters: /// - ocType: 类型 /// - defaultDateStr: <#defaultDateStr description#> /// - minDateStr: <#minDateStr description#> /// - maxDateStr: <#maxDateStr description#> /// - selectDateStrBlock: <#selectDateStrBlock description#> convenience init (ocType: MCDatePikerViewTypeForObject_c, defaultDateStr: String?, minDateStr: String?, maxDateStr: String?, selectDateStrBlock: ((_ dateStr: String?)->Void)?){ var defaultDate: Date = Date.init() var minDate: Date? var maxDate: Date? if !defaultDateStr.isEmptyStr { defaultDate = Date.init(defaultDateStr!) ?? Date.init() } if !minDateStr.isEmptyStr{ minDate = Date.init(minDateStr!) } if !maxDateStr.isEmptyStr{ maxDate = Date.init(maxDateStr!) } self.init(ocType: ocType, default: defaultDate, min: minDate, max: maxDate) self.selectDateStrBlock = selectDateStrBlock } convenience init (ocType: MCDatePikerViewTypeForObject_c, default defaultDate: Date = Date.init(), min minDate: Date? = nil, max maxDate: Date? = nil){ let dateType : MCDatePikerView.DateType switch ocType { case .yyyyMM: dateType = .yyyyMM case .yyyyMMdd: dateType = .yyyyMMdd case .HHmm: dateType = .HHmm case .HHmmss: dateType = .HHmmss case .yyyyMMddHHmm: dateType = .yyyyMMddHHmm case .yyyyMMddHHmmss: dateType = .yyyyMMddHHmmss } self.init(type: dateType, default: defaultDate, min: minDate, max: maxDate) } init(type dateType: MCDatePikerView.DateType, default defaultDate: Date = Date.init(), min minDate: Date? = nil, max maxDate: Date? = nil) { self.defaultDate = defaultDate super.init(frame: CGRect.zero) self.type = dateType self.minDate = minDate self.maxDate = maxDate if let minDate = minDate { if self.defaultDate < minDate{ self.defaultDate = minDate } } if let maxDate = maxDate { if self.defaultDate > maxDate{ self.defaultDate = maxDate } } if dateType != .HHmm && dateType != .HHmmss{ self.delegate = MCDatePikerDelegateImp_yyyyMM.init() } else { self.delegate = MCDatePikerDelegateImp_HHmm.init() } self.delegate?.defaultDate = self.defaultDate self.delegate?.maxDate = self.maxDate self.delegate?.minDate = self.minDate self.delegate?.style = self self.createUI() self.resetPikerViewCurrentDate() } enum DateType:String{ case yyyyMM = "yyyy-MM" case yyyyMMdd = "yyyy-MM-dd" case HHmm = "HH:mm" case HHmmss = "HH:mm:ss" case yyyyMMddHHmm = "yyyy-MM-dd HH:mm" case yyyyMMddHHmmss = "yyyy-MM-dd HH:mm:ss" } var dateType: MCDatePikerView.DateType{ self.type } //MARK: - Private Property /// 最小 private var minDate : Date? /// 最大 private var maxDate : Date? /// 默认日期 private var defaultDate : Date /// <#Description#> lazy private var pikerView : UIPickerView! = { let pikerView = UIPickerView.init(frame: CGRect.zero) pikerView.delegate = self.delegate pikerView.dataSource = self.delegate pikerView.backgroundColor = self.delegateForPikerBackgroundColor() return pikerView }() private var type : MCDatePikerView.DateType = .yyyyMM private var delegate : MCDatePikerDelegate! //MARK: - MCPopBeAssociatedDelegate /// 是否显示 var isShow: Bool! = false /// 信号 : show or hidden var binderIsShow: PublishSubject! = PublishSubject.init() /// 信号 : 选中了字符串 var binderValue: PublishSubject? = PublishSubject.init() var binderValues: PublishSubject<[MCPopSelectedModel]?>? = PublishSubject.init() @discardableResult func show() -> Self{ self.isShow = true self.binderIsShow.onNext(true) let window = kAppDelegateWindow window.addSubview(self) self.mas_makeConstraints { make in make?.edges.mas_equalTo()(window) } return self } func hidden(){ self.isShow = false self.binderIsShow.onNext(false) self.removeFromSuperview() } func sendSingle(with str: String) { let date = str.toDate() if let date = date{ //处理pikerview选择 self.defaultDate = date.date self.delegate?.defaultDate = self.defaultDate self.resetPikerViewCurrentDate() var dataSources: [MCPopSelectedModel] = [] switch self.dateType { case .yyyyMM: dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.year), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.month), index: nil)) case .yyyyMMdd: dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.year), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.month), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.day), index: nil)) case .yyyyMMddHHmm: dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.year), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.month), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.day), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.hour), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.minute), index: nil)) case .yyyyMMddHHmmss: dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.year), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.month), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.day), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.hour), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.minute), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.second), index: nil)) case .HHmm: dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.hour), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.minute), index: nil)) case .HHmmss: dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.hour), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.minute), index: nil)) dataSources.append(MCPopSelectedModel.init(name: Convert.toString(date.second), index: nil)) } self.binderValue?.onNext(MCPopSelectedModel.init(name: date.toFormat(self.getDateFormatter()), index: nil)) self.binderValues?.onNext(dataSources) } else{ self.binderValue?.onNext(nil) self.binderValues?.onNext(nil) } } /// 设置数据源 不可操作 /// - Parameter sources: <#sources description#> func setDataSource(with sources: T) -> Bool { return false } /// 获取数据源 /// - Returns: <#description#> func getDataSource() -> Any?{ return [] } //MARK: - required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit{ DLog("\(self) dealloc") } } extension MCDatePikerView{ private func createUI(){ //背景view let backgroundView = UIControl.init(frame: CGRect.zero) backgroundView.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 0.3) self.addSubview(backgroundView) backgroundView.mas_makeConstraints { make in make?.edges.mas_equalTo()(self) } _ = backgroundView.rx.controlEvent(.touchUpInside).takeUntil(self.rx.deallocated).subscribe(onNext:{[unowned self] in self.hidden() }) let contentView = UIView.init(frame: CGRect.zero) contentView.isUserInteractionEnabled = true contentView.backgroundColor = self.delegateForPikerBackgroundColor() self.addSubview(contentView) contentView.mas_makeConstraints { make in make?.left.right().bottom().mas_equalTo()(self) } contentView.addSubview(pikerView) pikerView.mas_makeConstraints { make in make?.left.right().mas_equalTo()(contentView) make?.height.offset()(self.delegateForPikerHeight()) make?.bottom.mas_equalTo()(contentView)?.offset()(-self.delegateForPikerViewBottomSpace()) } let toolBar = UIView.init(frame: CGRect.zero) toolBar.backgroundColor = self.delegateForToolBarBackgroundColor() contentView.addSubview(toolBar) toolBar.mas_makeConstraints { make in make?.left.right().mas_equalTo()(contentView) make?.height.offset()(self.delegateForToolBarHeight()) make?.bottom.mas_equalTo()(self.pikerView.mas_top) make?.top.mas_equalTo()(contentView) } let cancelBtn = UIButton.init(type: UIButton.ButtonType.custom) cancelBtn.setTitle(self.delegateForCancelTitle(), for: .normal) cancelBtn.setTitleColor(self.delegateForCancelTitleColor(), for: .normal) cancelBtn.titleLabel?.font = self.delegateForCancelTitleFont() cancelBtn.backgroundColor = self.delegateForCancelBackgroundColor() toolBar.addSubview(cancelBtn) cancelBtn.mas_makeConstraints { make in make?.left.mas_equalTo()(toolBar)?.offset()(self.delegateForToolBarItemMarginLeftSpace()) make?.top.mas_equalTo()(toolBar)?.offset()(self.delegateForToolBarItemMarginTopSpace()) make?.bottom.mas_equalTo()(toolBar)?.offset()(-self.delegateForToolBarItemMarginTopSpace()) make?.width.offset()(self.delegateForToolBarItemWidth()) } _ = cancelBtn.rx.tap.takeUntil(self.rx.deallocated).subscribe(onNext:{[unowned self] in self.hidden() }) let okBtn = UIButton.init(type: UIButton.ButtonType.custom) okBtn.setTitle(self.delegateForOKTitle(), for: .normal) okBtn.setTitleColor(self.delegateForOKTitleColor(), for: .normal) okBtn.titleLabel?.font = self.delegateForOKTitleFont() okBtn.backgroundColor = self.delegateForOKBackgroundColor() toolBar.addSubview(okBtn) okBtn.mas_makeConstraints { make in make?.right.mas_equalTo()(toolBar)?.offset()(-self.delegateForToolBarItemMarginLeftSpace()) make?.top.mas_equalTo()(toolBar)?.offset()(self.delegateForToolBarItemMarginTopSpace()) make?.bottom.mas_equalTo()(toolBar)?.offset()(-self.delegateForToolBarItemMarginTopSpace()) make?.width.offset()(self.delegateForToolBarItemWidth()) } _ = okBtn.rx.tap.takeUntil(self.rx.deallocated).subscribe(onNext:{[unowned self] in let date = self.delegate.finallyDate let dateStr = date.toFormat(self.getDateFormatter()) self.sendSingle(with: dateStr) self.selectBlock?(date) self.selectDateStrBlock?(dateStr) self.hidden() }) } /// pikerView 设置当前选中的时间 private func resetPikerViewCurrentDate(){ self.pikerView?.reloadAllComponents() if self.dateType != .HHmm && self.dateType != .HHmmss{ self.pikerView?.selectRow(self.defaultDate.year - 1, inComponent: 0, animated: false) self.pikerView?.selectRow(self.delegate.getAdjustMonth(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 1) / 2, targetMonth: self.delegate.month), inComponent: 1, animated: false) let components = self.delegate.numberOfComponents(in: self.pikerView) if components > 2{ 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) } if components > 3{ self.pikerView?.selectRow(self.delegate.getAdjustHour(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 3) / 2, targetHour: self.delegate.hour), inComponent: 3, animated: false) } if components > 4{ self.pikerView?.selectRow(self.delegate.getAdjustMinute(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 4) / 2, targetMinute: self.delegate.minute), inComponent: 4, animated: false) } if components > 5{ self.pikerView?.selectRow(self.delegate.getAdjustSeconds(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 5) / 2, targetSeconds: self.delegate.seconds), inComponent: 5, animated: false) } } else{ self.pikerView?.selectRow(self.delegate.getAdjustHour(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 0) / 2, targetHour: self.delegate.hour), inComponent: 0, animated: false) self.pikerView?.selectRow(self.delegate.getAdjustMinute(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 1) / 2, targetMinute: self.delegate.minute), inComponent: 1, animated: false) if self.delegate.numberOfComponents(in: self.pikerView) > 2{ self.pikerView?.selectRow(self.delegate.getAdjustSeconds(row: self.delegate.pickerView(self.pikerView, numberOfRowsInComponent: 2) / 2, targetSeconds: self.delegate.seconds), inComponent: 2, animated: false) } } } private func getDateFormatter() -> String{ var dateFormatter : String switch self.dateType { case .yyyyMM: dateFormatter = "yyyy-MM" case .yyyyMMdd: dateFormatter = "yyyy-MM-dd" case .yyyyMMddHHmm: dateFormatter = "yyyy-MM-dd HH:mm" case .yyyyMMddHHmmss: dateFormatter = "yyyy-MM-dd HH:mm:ss" case .HHmm: dateFormatter = "HH:mm" case .HHmmss: dateFormatter = "HH:mm:ss" } return dateFormatter } @objc(setSwiftDateRegion) public class func setSwiftDateRegion(){ SwiftDate.defaultRegion = .local } }