Open leonluc-dev opened 4 years ago
Added support for iOS 13 Dark mode with bug fixes in datepickerdialog ios #97 changes :
`//
// DatePickerDialog.swift
//
//
// Created by Yagbhan Singh on 10/01/20.
// Copyright © 2020 Yagbhan Singh. All rights reserved.
//
import Foundation import UIKit
private extension Selector { static let buttonTapped = #selector(DatePickerDialog.buttonTapped) static let deviceOrientationDidChange = #selector(DatePickerDialog.deviceOrientationDidChange) }
public class DatePickerDialog: UIView { public typealias DatePickerCallback = (_ date: Date?) -> Void
// MARK: - Constants
private let kDatePickerDialogDefaultButtonHeight: CGFloat = 50
private let kDatePickerDialogDefaultButtonSpacerHeight: CGFloat = 1
private let kDatePickerDialogCornerRadius: CGFloat = 7
private let kDatePickerDialogDoneButtonTag: Int = 1
// MARK: - Views
public var dialogView: UIView!
public var dialogContainer: UIView!
private var titleLabel: UILabel!
public var datePicker: UIDatePicker!
private var cancelButton: UIButton!
private var doneButton: UIButton!
private var linelbl: UILabel!
// MARK: - Variables
private var defaultDate: Date?
private var datePickerMode: UIDatePicker.Mode?
private var callback: DatePickerCallback?
// MARK: - Dialog initialization
override init(frame: CGRect) {
super.init(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height))
setupView()
}
required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupView() {
self.dialogView = createContainerView()
self.dialogView!.layer.shouldRasterize = true
self.dialogView!.layer.rasterizationScale = UIScreen.main.scale
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
self.dialogView!.layer.opacity = 0.5
self.dialogView!.layer.transform = CATransform3DMakeScale(1.3, 1.3, 1)
self.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
self.addSubview(self.dialogView!)
NotificationCenter.default.addObserver(self, selector: #selector(self.CheckHeaderanimation1), name: NSNotification.Name(rawValue: "receivedatefinal"), object: nil)
}
/// Create the dialog view, and animate opening the dialog
public func show(title: String, doneButtonTitle: String = "Done", cancelButtonTitle: String = "Cancel", defaultDate: Date = Date(), minimumDate: Date? = nil, maximumDate: Date? = nil, datePickerMode: UIDatePicker.Mode = .date, callback: @escaping DatePickerCallback) {
self.titleLabel.text = title
// self.titleLabel.textColor = UIColor.black
self.doneButton.setTitle(doneButtonTitle, for: .normal)
self.cancelButton.setTitle(cancelButtonTitle, for: .normal)
self.datePickerMode = datePickerMode
self.callback = callback
self.datePicker.addTarget(self, action: #selector(self.datePickerValueChanged), for: UIControl.Event.valueChanged)
self.datePicker.timeZone = NSTimeZone.local
self.datePicker.datePickerMode = self.datePickerMode ?? .date
let currentDate = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
formatter.locale = Locale.init(identifier: "en_GB")
let datepickerdate = formatter.string(from: currentDate) as NSString
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd HH:mm:ss"
df.locale = Locale.init(identifier: "en_GB")
let date = df.date(from: datepickerdate as String)
if let unwrappedDate = date {
self.datePicker.setDate(unwrappedDate, animated: false)
self.datePicker.maximumDate = unwrappedDate
}
self.datePicker.minimumDate = minimumDate
/* Add dialog to main window */
guard let appDelegate = UIApplication.shared.delegate else { fatalError() }
guard let window = appDelegate.window else { fatalError() }
window?.addSubview(self)
window?.bringSubviewToFront(self)
window?.endEditing(true)
NotificationCenter.default.addObserver(self, selector: .deviceOrientationDidChange, name: UIDevice.orientationDidChangeNotification, object: nil)
/* Anim */
UIView.animate(
withDuration: 0.2,
delay: 0,
options: .curveEaseInOut,
animations: {
self.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.4)
self.dialogView!.layer.opacity = 1
self.dialogView!.layer.transform = CATransform3DMakeScale(1, 1, 1)
}
)
}
@objc func datePickerValueChanged(sender:UIDatePicker)
{
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let datepickerdate = formatter.string(from: self.datePicker.date) as NSString
let userInfo: [AnyHashable: Any] = ["dateval": (datepickerdate)]
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "receivedate"), object: nil, userInfo: userInfo)
}
@objc func CheckHeaderanimation1(notification:NSNotification)
{
var tempdect = NSDictionary ()
tempdect = notification.userInfo! as NSDictionary
let str = tempdect.value(forKey: "dateval1")
self.titleLabel.text = str as? String
}
/// Dialog close animation then cleaning and removing the view from the parent
private func close() {
NotificationCenter.default.removeObserver(self)
let currentTransform = self.dialogView.layer.transform
let startRotation = (self.value(forKeyPath: "layer.transform.rotation.z") as? NSNumber) as? Double ?? 0.0
let rotation = CATransform3DMakeRotation((CGFloat)(-startRotation + .pi * 270 / 180), 0, 0, 0)
self.dialogView.layer.transform = CATransform3DConcat(rotation, CATransform3DMakeScale(1, 1, 1))
self.dialogView.layer.opacity = 1
UIView.animate(
withDuration: 0.2,
delay: 0,
options: [],
animations: {
self.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0)
self.dialogView.layer.transform = CATransform3DConcat(currentTransform, CATransform3DMakeScale(0.6, 0.6, 1))
self.dialogView.layer.opacity = 0
}) { (finished) in
for v in self.subviews {
v.removeFromSuperview()
}
self.removeFromSuperview()
self.setupView()
}
}
/// Creates the container view here: create the dialog, then add the custom content and buttons
public func createContainerView() -> UIView {
let screenSize = countScreenSize()
let dialogSize = CGSize(
width: 300,
height: 250
+ kDatePickerDialogDefaultButtonHeight
+ kDatePickerDialogDefaultButtonSpacerHeight)
// For the black background
self.frame = CGRect(x: 0, y: 0, width: screenSize.width, height: screenSize.height)
// This is the dialog's container; we attach the custom content and the buttons to this one
dialogContainer = UIView(frame: CGRect(x: (screenSize.width - dialogSize.width) / 2, y: (screenSize.height - dialogSize.height) / 2, width: 300, height: 300))
if #available(iOS 13.0, *) {
dialogContainer.backgroundColor = .systemBackground
} else {
// Fallback on earlier versions
}
dialogContainer.layer.cornerRadius = 7.0
dialogContainer.layer.borderWidth = 1.0
dialogContainer.layer.masksToBounds = true
dialogContainer.layer.borderColor = UIColor.lightGray.cgColor
if #available(iOS 13.0, *){
dialogContainer.layer.borderColor = UIColor.systemGray3.cgColor
}
else{
dialogContainer.layer.borderColor = UIColor(red: 198/255, green: 198/255, blue: 198/255, alpha: 1).cgColor
}
dialogContainer.layer.borderWidth = 1
dialogContainer.layer.shadowRadius = 7 + 5
dialogContainer.layer.shadowOpacity = 0.1
dialogContainer.layer.shadowOffset = CGSize(width: 0 - (7 + 5) / 2, height: 0 - ( 7 + 5) / 2)
dialogContainer.layer.shadowColor = UIColor.lightGray.cgColor
dialogContainer.layer.shadowPath = UIBezierPath(roundedRect: dialogContainer.bounds, cornerRadius: dialogContainer.layer.cornerRadius).cgPath
// There is a line above the button
let lineView = UIView(frame: CGRect(x: 0, y: dialogContainer.bounds.size.height - kDatePickerDialogDefaultButtonHeight - kDatePickerDialogDefaultButtonSpacerHeight, width: dialogContainer.bounds.size.width, height: kDatePickerDialogDefaultButtonSpacerHeight))
if #available(iOS 13.0, *){
lineView.backgroundColor = UIColor.systemGray3
}
else{
lineView.backgroundColor = UIColor(red: 198/255, green: 198/255, blue: 198/255, alpha: 1)
}
dialogContainer.addSubview(lineView)
//Title
self.titleLabel = UILabel(frame: CGRect(x: 10, y: 15, width: 280, height: 30))
self.titleLabel.textAlignment = .center
self.titleLabel.font = UIFont.boldSystemFont(ofSize: 21)
self.titleLabel.textColor = UIColor(red: 99/255, green: 182/255, blue: 225/255, alpha: 1)
dialogContainer.addSubview(self.titleLabel)
self.linelbl = UILabel(frame: CGRect(x: 0, y: 50, width: 300, height: 2))
//self.linelbl.textAlignment = .left
//self.linelbl.font = UIFont.boldSystemFont(ofSize: 21)
self.linelbl.backgroundColor = UIColor(red: 99/255, green: 182/255, blue: 225/255, alpha: 1)
dialogContainer.addSubview(self.linelbl)
self.datePicker = UIDatePicker(frame: CGRect(x: 0, y: 30, width: 0, height: 0))
self.datePicker.autoresizingMask = .flexibleRightMargin
self.datePicker.frame.size.width = 300
self.datePicker.frame.size.height = 250
dialogContainer.addSubview(self.datePicker)
// Add the buttons
addButtonsToView(container: dialogContainer)
return dialogContainer
}
/// Add buttons to container
private func addButtonsToView(container: UIView) {
let buttonWidth = container.bounds.size.width / 2
self.cancelButton = UIButton(type: .custom) as UIButton
self.cancelButton.frame = CGRect(
x: 0,
y: container.bounds.size.height - kDatePickerDialogDefaultButtonHeight,
width: buttonWidth,
height: kDatePickerDialogDefaultButtonHeight
)
self.cancelButton.setTitleColor(UIColor(red: 99/255, green: 182/255, blue: 225/255, alpha: 1), for: .normal)
self.cancelButton.setTitleColor(UIColor(red: 99/255, green: 182/255, blue: 225/255, alpha: 1), for: .highlighted)
self.cancelButton.titleLabel!.font = UIFont.boldSystemFont(ofSize: 18)
self.cancelButton.layer.cornerRadius = kDatePickerDialogCornerRadius
self.cancelButton.addTarget(self, action: .buttonTapped, for: .touchUpInside)
container.addSubview(self.cancelButton)
self.doneButton = UIButton(type: .custom) as UIButton
self.doneButton.frame = CGRect(
x: buttonWidth,
y: container.bounds.size.height - kDatePickerDialogDefaultButtonHeight,
width: buttonWidth,
height: kDatePickerDialogDefaultButtonHeight
)
self.doneButton.tag = kDatePickerDialogDoneButtonTag
self.doneButton.setTitleColor(UIColor(red: 99/255, green: 182/255, blue: 225/255, alpha: 1), for: .normal)
self.doneButton.setTitleColor(UIColor(red: 99/255, green: 182/255, blue: 225/255, alpha: 1), for: .highlighted)
self.doneButton.titleLabel!.font = UIFont.boldSystemFont(ofSize: 18)
self.doneButton.layer.cornerRadius = kDatePickerDialogCornerRadius
self.doneButton.addTarget(self, action: .buttonTapped, for: .touchUpInside)
container.addSubview(self.doneButton)
}
@objc func buttonTapped(sender: UIButton!) {
if sender.tag == kDatePickerDialogDoneButtonTag {
self.callback?(self.datePicker.date)
} else {
self.callback?(nil)
}
close()
}
// MARK: - Helpers
/// Count and return the screen's size
func countScreenSize() -> CGSize {
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
return CGSize(width: screenWidth, height: screenHeight)
}
} `
This PR is to add support for the new iOS 13 Dark mode.
Changes made:
Changed color references to dynamic iOS 13 colors (with #available check for iOS 12 and earlier support)
Default color assignment in initializer moved to functions so availability check can be applied