squimer / DatePickerDialog-iOS-Swift

Date picker dialog for iOS
MIT License
580 stars 177 forks source link

Added support for iOS 13 Dark Mode #97

Open leonluc-dev opened 4 years ago

leonluc-dev commented 4 years ago

This PR is to add support for the new iOS 13 Dark mode.

Changes made:

YagbhanSingh commented 4 years ago

Added support for iOS 13 Dark mode with bug fixes in datepickerdialog ios #97 changes :

  1. dialog view frame changes issue resolved .
  2. dark mode bug fixes.

Support for iOS 13 Dark mode with bug fixes #97

`// // 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)
}

} `