LWDatePickerDialog.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. //
  2. // LWDatePickerDialog.swift
  3. // DatePickerDialogSwift
  4. //
  5. // Created by 刘振兴 on 2018/1/17.
  6. //
  7. import UIKit
  8. private extension Selector {
  9. //按钮点击
  10. static let buttonTapped = #selector(LWDatePickerDialog.buttonTapped)
  11. //设备方向转换
  12. static let deviceOrientationDidChange = #selector(LWDatePickerDialog.deviceOrientationDidChange)
  13. }
  14. struct LWDialogStyle {
  15. //title
  16. static let titleColor = UIColor(hex: "#FFFFFF")
  17. static let titleTextFont = UIFont(name: "PingFangSC-Regular", size: 18)
  18. static var titleViewBackColor: UIColor {
  19. get {
  20. return O2ThemeManager.color(for: "Base.base_color")!
  21. }
  22. }
  23. //DatePicker unSelected TextColor Font
  24. static let dpUnSelTextColor = UIColor(hex: "#999999")
  25. static let dpUnSelTextFont = UIFont(name: "PingFangSC-Regular", size: 18)
  26. static var dpSelTextColor: UIColor {
  27. get {
  28. return O2ThemeManager.color(for: "Base.base_color")!
  29. }
  30. }
  31. static let dpSelTextFont = UIFont(name: "PingFangSC-Regular", size: 23)
  32. //button
  33. static let okButtonTextColor = UIColor(hex: "#FFFFFF")
  34. static let okButtonFont = UIFont(name: "PingFangSC-Regular", size: 16)
  35. static var okButtonBackColor: UIColor {
  36. get {
  37. return O2ThemeManager.color(for: "Base.base_color")!
  38. }
  39. }
  40. static let cancelButtonTextColor = UIColor(hex: "#FFFFFF")
  41. static let cancelButtonFont = UIFont(name: "PingFangSC-Regular", size: 16)
  42. static let cancelButtonBackColor = UIColor(hex: "#CCCCCC")
  43. // MARK: - Constants
  44. static let defaultWidth:CGFloat = 300
  45. static let defaultTitleContainerHeight:CGFloat = 50
  46. static let defaultTitleHeight:CGFloat = 35
  47. static let defaultDatePickerHeight:CGFloat = 230
  48. static let defaultButtonContainerHeight:CGFloat = 50
  49. static let defaultButtonHeight: CGFloat = 35
  50. static let defaultButtonSpacerHeight: CGFloat = 1
  51. static let cornerRadius: CGFloat = 15
  52. static let doneButtonTag: Int = 1
  53. }
  54. open class LWDatePickerDialog: UIView {
  55. //回调类型定义
  56. public typealias DatePickerCallback = ( Date? ) -> Void
  57. // MARK: - Views
  58. private var dialogView: UIView!
  59. //title view
  60. private var titleContainerView:UIView!
  61. private var titleLabel: UILabel!
  62. //picker view
  63. open var datePicker: UIDatePicker!
  64. //button view
  65. private var buttonContainerView:UIView!
  66. private var cancelButton: UIButton!
  67. private var doneButton: UIButton!
  68. // MARK: - Variables
  69. private var defaultDate: Date?
  70. private var datePickerMode: UIDatePicker.Mode?
  71. private var callback: DatePickerCallback?
  72. var showCancelButton: Bool = false
  73. var locale: Locale?
  74. private var textColor: UIColor!
  75. private var buttonColor: UIColor!
  76. private var font: UIFont!
  77. // MARK: - Dialog initialization
  78. public init(textColor: UIColor = UIColor.black,
  79. buttonColor: UIColor = UIColor.blue,
  80. font: UIFont = .boldSystemFont(ofSize: 15),
  81. locale: Locale? = nil,
  82. showCancelButton: Bool = true) {
  83. let size = UIScreen.main.bounds.size
  84. super.init(frame: CGRect(x: 0, y: 0, width: size.width, height: size.height))
  85. self.textColor = textColor
  86. self.buttonColor = buttonColor
  87. self.font = font
  88. self.showCancelButton = showCancelButton
  89. self.locale = locale
  90. setupView()
  91. }
  92. required public init?(coder aDecoder: NSCoder) {
  93. super.init(coder: aDecoder)
  94. }
  95. func setupView() {
  96. self.dialogView = createContainerView()
  97. self.dialogView!.layer.shouldRasterize = true
  98. self.dialogView!.layer.rasterizationScale = UIScreen.main.scale
  99. self.layer.shouldRasterize = true
  100. self.layer.rasterizationScale = UIScreen.main.scale
  101. self.dialogView!.layer.opacity = 0.5
  102. self.dialogView!.layer.transform = CATransform3DMakeScale(1.3, 1.3, 1)
  103. self.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
  104. self.addSubview(self.dialogView!)
  105. }
  106. /// Handle device orientation changes
  107. @objc func deviceOrientationDidChange(_ notification: Notification) {
  108. self.frame = UIScreen.main.bounds
  109. let dialogSize = CGSize(width: LWDialogStyle.defaultWidth,height: LWDialogStyle.defaultTitleContainerHeight + LWDialogStyle.defaultDatePickerHeight + LWDialogStyle.defaultButtonContainerHeight)
  110. dialogView.frame = CGRect(x: (UIScreen.main.bounds.size.width - dialogSize.width) / 2,
  111. y: (UIScreen.main.bounds.size.height - dialogSize.height) / 2,
  112. width: dialogSize.width,
  113. height: dialogSize.height)
  114. }
  115. /// Create the dialog view, and animate opening the dialog
  116. open func show(_ title: String,
  117. doneButtonTitle: String = "Done",
  118. cancelButtonTitle: String = "Cancel",
  119. defaultDate: Date = Date(),
  120. minimumDate: Date? = nil, maximumDate: Date? = nil,
  121. datePickerMode: UIDatePicker.Mode = .dateAndTime,
  122. callback: @escaping DatePickerCallback) {
  123. self.titleLabel.text = title
  124. self.doneButton.setTitle(doneButtonTitle, for: .normal)
  125. if showCancelButton {
  126. self.cancelButton.setTitle(cancelButtonTitle, for: .normal)
  127. }
  128. self.datePickerMode = datePickerMode
  129. self.callback = callback
  130. self.defaultDate = defaultDate
  131. self.datePicker.datePickerMode = self.datePickerMode ?? UIDatePicker.Mode.date
  132. self.datePicker.date = self.defaultDate ?? Date()
  133. self.datePicker.maximumDate = maximumDate
  134. self.datePicker.minimumDate = minimumDate
  135. if let locale = self.locale {
  136. self.datePicker.locale = locale
  137. }
  138. /* Add dialog to main window */
  139. guard let appDelegate = UIApplication.shared.delegate else { fatalError() }
  140. guard let window = appDelegate.window else { fatalError() }
  141. window?.addSubview(self)
  142. window?.bringSubviewToFront(self)
  143. window?.endEditing(true)
  144. NotificationCenter.default.addObserver(self,
  145. selector: .deviceOrientationDidChange,
  146. name: UIDevice.orientationDidChangeNotification,
  147. object: nil)
  148. /* Anim */
  149. UIView.animate(
  150. withDuration: 0.2,
  151. delay: 0,
  152. options: .curveEaseInOut,
  153. animations: {
  154. self.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
  155. self.dialogView!.layer.opacity = 1
  156. self.dialogView!.layer.transform = CATransform3DMakeScale(1, 1, 1)
  157. }
  158. )
  159. }
  160. /// Dialog close animation then cleaning and removing the view from the parent
  161. private func close() {
  162. let currentTransform = self.dialogView.layer.transform
  163. let startRotation = (self.value(forKeyPath: "layer.transform.rotation.z") as? NSNumber) as? Double ?? 0.0
  164. let rotation = CATransform3DMakeRotation((CGFloat)(-startRotation + .pi * 270 / 180), 0, 0, 0)
  165. self.dialogView.layer.transform = CATransform3DConcat(rotation, CATransform3DMakeScale(1, 1, 1))
  166. self.dialogView.layer.opacity = 1
  167. UIView.animate(
  168. withDuration: 0.2,
  169. delay: 0,
  170. options: [],
  171. animations: {
  172. self.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
  173. let transform = CATransform3DConcat(currentTransform, CATransform3DMakeScale(0.6, 0.6, 1))
  174. self.dialogView.layer.transform = transform
  175. self.dialogView.layer.opacity = 0
  176. }) { (_) in
  177. for v in self.subviews {
  178. v.removeFromSuperview()
  179. }
  180. self.removeFromSuperview()
  181. self.setupView()
  182. }
  183. }
  184. /// Creates the container view here: create the dialog, then add the custom content and buttons
  185. private func createContainerView() -> UIView {
  186. let screenSize = UIScreen.main.bounds.size
  187. //title + datePicker + button height
  188. let dialogSize = CGSize(width: LWDialogStyle.defaultWidth, height: LWDialogStyle.defaultTitleContainerHeight + LWDialogStyle.defaultDatePickerHeight + LWDialogStyle.defaultButtonContainerHeight)
  189. // For the black background
  190. self.frame = CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height)
  191. // This is the dialog's container; we attach the custom content and the buttons to this one
  192. let container = UIView(frame: CGRect(x: (screenSize.width - dialogSize.width) / 2,
  193. y: (screenSize.height - dialogSize.height) / 2,
  194. width: dialogSize.width,
  195. height: dialogSize.height))
  196. // First, we style the dialog to match the iOS8 UIAlertView >>>
  197. let gradient: CAGradientLayer = CAGradientLayer(layer: self.layer)
  198. gradient.frame = container.bounds
  199. gradient.colors = [UIColor(red: 218/255, green: 218/255, blue: 218/255, alpha: 1).cgColor,
  200. UIColor(red: 233/255, green: 233/255, blue: 233/255, alpha: 1).cgColor,
  201. UIColor(red: 218/255, green: 218/255, blue: 218/255, alpha: 1).cgColor]
  202. let cornerRadius = LWDialogStyle.cornerRadius
  203. gradient.cornerRadius = cornerRadius
  204. container.layer.insertSublayer(gradient, at: 0)
  205. container.layer.cornerRadius = cornerRadius
  206. container.layer.masksToBounds = true
  207. container.layer.borderColor = UIColor(red: 198/255, green: 198/255, blue: 198/255, alpha: 1).cgColor
  208. container.layer.borderWidth = 1
  209. container.layer.shadowRadius = cornerRadius + 5
  210. container.layer.shadowOpacity = 0.1
  211. container.layer.shadowOffset = CGSize(width: 0 - (cornerRadius + 5) / 2, height: 0 - (cornerRadius + 5) / 2)
  212. container.layer.shadowColor = UIColor.black.cgColor
  213. container.layer.shadowPath = UIBezierPath(roundedRect: container.bounds,
  214. cornerRadius: container.layer.cornerRadius).cgPath
  215. // There is a line above the button
  216. // let yPosition = container.bounds.size.height - kDefaultButtonHeight - kDefaultButtonSpacerHeight
  217. // let lineView = UIView(frame: CGRect(x: 0,
  218. // y: yPosition,
  219. // width: container.bounds.size.width,
  220. // height: kDefaultButtonSpacerHeight))
  221. // lineView.backgroundColor = UIColor(red: 198/255, green: 198/255, blue: 198/255, alpha: 1)
  222. // container.addSubview(lineView)
  223. //Title
  224. self.titleContainerView = UIView(frame: CGRect(x: 0, y: 0, width: LWDialogStyle.defaultWidth, height: LWDialogStyle.defaultTitleContainerHeight))
  225. self.titleContainerView.backgroundColor = LWDialogStyle.titleViewBackColor
  226. self.titleLabel = UILabel(frame: CGRect(x: 20, y: (LWDialogStyle.defaultTitleContainerHeight-LWDialogStyle.defaultTitleHeight)/2, width: LWDialogStyle.defaultWidth - 50, height: LWDialogStyle.defaultTitleHeight))
  227. self.titleLabel.textAlignment = .left
  228. self.titleLabel.textColor = LWDialogStyle.titleColor
  229. self.titleLabel.font = LWDialogStyle.titleTextFont
  230. self.titleContainerView.addSubview(self.titleLabel)
  231. container.addSubview(self.titleContainerView)
  232. //DatePicker
  233. self.datePicker = configuredDatePicker()
  234. container.addSubview(self.datePicker)
  235. // Add the buttons
  236. self.buttonContainerView = UIView(frame: CGRect(x: 0, y: LWDialogStyle.defaultTitleContainerHeight + LWDialogStyle.defaultDatePickerHeight, width: LWDialogStyle.defaultWidth, height: LWDialogStyle.defaultButtonContainerHeight))
  237. self.backgroundColor = UIColor.white
  238. addButtonsToView(container: buttonContainerView)
  239. container.addSubview(self.buttonContainerView)
  240. return container
  241. }
  242. fileprivate func configuredDatePicker() -> UIDatePicker {
  243. let datePicker = UIDatePicker(frame: CGRect(x: 0, y: LWDialogStyle.defaultTitleContainerHeight, width: 0, height: 0))
  244. datePicker.setValue(LWDialogStyle.dpSelTextColor, forKeyPath: "textColor")
  245. datePicker.autoresizingMask = .flexibleRightMargin
  246. datePicker.frame.size.width = LWDialogStyle.defaultWidth
  247. datePicker.frame.size.height = LWDialogStyle.defaultDatePickerHeight
  248. return datePicker
  249. }
  250. /// Add buttons to container
  251. private func addButtonsToView(container: UIView) {
  252. var buttonWidth = (container.bounds.size.width - 20*2) / 2
  253. var leftButtonFrame = CGRect(
  254. x: 10,
  255. y: (container.bounds.size.height - LWDialogStyle.defaultButtonHeight)/2,
  256. width: buttonWidth,
  257. height: LWDialogStyle.defaultButtonHeight
  258. )
  259. var rightButtonFrame = CGRect(
  260. x: 10 + buttonWidth + 10 * 2,
  261. y: (container.bounds.size.height - LWDialogStyle.defaultButtonHeight)/2,
  262. width: buttonWidth,
  263. height: LWDialogStyle.defaultButtonHeight
  264. )
  265. if showCancelButton == false {
  266. buttonWidth = container.bounds.size.width
  267. leftButtonFrame = CGRect()
  268. rightButtonFrame = CGRect(
  269. x: (LWDialogStyle.defaultWidth - buttonWidth) / 2,
  270. y: (container.bounds.size.height - LWDialogStyle.defaultButtonHeight)/2,
  271. width: buttonWidth,
  272. height: LWDialogStyle.defaultButtonHeight
  273. )
  274. }
  275. let interfaceLayoutDirection = UIApplication.shared.userInterfaceLayoutDirection
  276. let isLeftToRightDirection = interfaceLayoutDirection == .leftToRight
  277. if showCancelButton {
  278. self.cancelButton = UIButton(type: .custom) as UIButton
  279. self.cancelButton.frame = isLeftToRightDirection ? leftButtonFrame : rightButtonFrame
  280. self.cancelButton.setTitleColor(LWDialogStyle.cancelButtonTextColor, for: .normal)
  281. self.cancelButton.setTitleColor(LWDialogStyle.cancelButtonTextColor, for: .highlighted)
  282. self.cancelButton.backgroundColor = LWDialogStyle.cancelButtonBackColor
  283. self.cancelButton.titleLabel!.font = LWDialogStyle.cancelButtonFont
  284. self.cancelButton.layer.cornerRadius = LWDialogStyle.cornerRadius
  285. self.cancelButton.addTarget(self, action: .buttonTapped, for: .touchUpInside)
  286. container.addSubview(self.cancelButton)
  287. }
  288. self.doneButton = UIButton(type: .custom) as UIButton
  289. self.doneButton.frame = isLeftToRightDirection ? rightButtonFrame : leftButtonFrame
  290. self.doneButton.tag = LWDialogStyle.doneButtonTag
  291. self.doneButton.backgroundColor = LWDialogStyle.okButtonBackColor
  292. self.doneButton.setTitleColor(LWDialogStyle.okButtonTextColor, for: .normal)
  293. self.doneButton.setTitleColor(LWDialogStyle.okButtonTextColor, for: .highlighted)
  294. self.doneButton.titleLabel!.font = LWDialogStyle.okButtonFont
  295. self.doneButton.layer.cornerRadius = LWDialogStyle.cornerRadius
  296. self.doneButton.addTarget(self, action: .buttonTapped, for: .touchUpInside)
  297. container.addSubview(self.doneButton)
  298. }
  299. @objc func buttonTapped(sender: UIButton!) {
  300. if sender.tag == LWDialogStyle.doneButtonTag {
  301. self.callback?(self.datePicker.date)
  302. } else {
  303. self.callback?(nil)
  304. }
  305. close()
  306. }
  307. deinit {
  308. NotificationCenter.default.removeObserver(self)
  309. }
  310. }