12.6 C
New York
Wednesday, October 16, 2024

DatePicker Validation – Native iOS – Swift


Right here is the code that I’ve carried out in native iOS Swift:

class DateFilterViewController: BaseViewController, DateFilterView {

// MARK: - Non-public properties
@IBOutlet weak var crossButton: UIButton?
@IBOutlet weak var segmentView: UIView?
@IBOutlet weak var startLabel: UILabel?
@IBOutlet weak var startDateField: BorderedTextField?
@IBOutlet weak var endLabel: UILabel?
@IBOutlet weak var endDateField: BorderedTextField?
@IBOutlet weak var mainButton: UIButton?

var segementControl: UISegmentedControl?
personal let look: DateFilterAppearance?
personal let datePickerStart = UIDatePicker()
personal let datePickerEnd = UIDatePicker()
personal var isSelectedSegment = false
personal var startSelectedDate = Date()
personal var endSelectedDate = Date()
personal let sprint = DateUtil.dashDataFormat, slash = DateUtil.slashDataFormat

// MARK: - Public properties
var output: DateFilterViewOutput!

// MARK: - Initialization / Deinitialization
init(look: DateFilterAppearance?) {
    self.look = look
    tremendous.init(nibName: "DateFilterView", bundle: nil)
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been applied")
}

// MARK: - UIViewController
override func viewDidLoad() {
    tremendous.viewDidLoad()
    title = localizedKey(key: "title")
    self.navigationController?.isNavigationBarHidden = false
    if let show = self.look {
        setViewAppearance(look: show)
    }
    startDateField?.dropdownButton(completionHandler: {
        if let subject = self.startDateField {
            self.callDatePicker(textField: subject)
        }
    })
    endDateField?.dropdownButton(completionHandler: {
        if let subject = self.endDateField {
            self.callDatePicker(textField: subject)
        }
    })
}

// MARK: - DateFilterView
var dates: [Dates]? = [] {
    didSet {
    }
}
var confirmDates: Dates? {
    didSet {
        output.confirmDates = confirmDates
    }
}

personal func callDatePicker(textField: UITextField) {
    textField.keyboardToolbar.tintColor = UIColor.black
    if textField == startDateField {
        datePickerStart.datePickerMode = UIDatePicker.Mode.date
        if #out there(iOS 13.4, *) {
            datePickerStart.preferredDatePickerStyle = .wheels
        }
        textField.becomeFirstResponder()
        textField.inputView = datePickerStart
        datePickerStart.addTarget(self, motion: #selector(handleStartDatePicker), for: UIControl.Occasion.valueChanged)
        textField.addDoneOnKeyboardWithTarget(self, motion: #selector(donePickerStart))
        if let sDate = showSelectedDate(textField: textField) {
            datePickerStart.date = sDate
        }
    } else {
        datePickerEnd.datePickerMode = UIDatePicker.Mode.date
        if #out there(iOS 13.4, *) {
            datePickerEnd.preferredDatePickerStyle = .wheels
        }
        textField.becomeFirstResponder()
        textField.inputView = datePickerEnd
        datePickerEnd.addTarget(self, motion: #selector(handleEndDatePicker), for: UIControl.Occasion.valueChanged)
        textField.addDoneOnKeyboardWithTarget(self, motion: #selector(donePickerEnd))
        if let eDate = showSelectedDate(textField: textField) {
            datePickerEnd.date = eDate
        }
    }
}

personal func showSelectedDate(textField: UITextField) -> Date? {
    if let sDateString = textField.textual content, sDateString.depend > 0 {
        return DateUtil.getDateFromString(string: sDateString, timeFormat: DateUtil.slashDataFormat)
    }
    return nil
}

// MARK: - Non-public strategies
@objc personal func donePickerStart() {
    self.view.endEditing(true)
    guard let sDate = startDateField?.textual content, !sDate.isEmpty else {
        self.startDateField?.textual content = DateUtil.convertStringFromDate(date: datePickerStart.date)
        return
    }
}

@objc personal func donePickerEnd() {
    self.view.endEditing(true)
    guard let eDate = endDateField?.textual content, !eDate.isEmpty else {
        self.endDateField?.textual content = DateUtil.convertStringFromDate(date: datePickerEnd.date)
        return
    }
}

personal func validateDate() {
    guard let sDate = startDateField?.textual content, !sDate.isEmpty else {
        let sRequire = localizedKey(key: "from.require")
        self.displayMessage(title: "", message: sRequire, actions: [MessageAction.okAction()])
        return
    }
    guard let eDate = endDateField?.textual content, !eDate.isEmpty else {
        let sRequire = localizedKey(key: "to.require")
        self.displayMessage(title: "", message: sRequire, actions: [MessageAction.okAction()])
        return
    }
}

@IBAction func onClickConfirmButton(_ sender: UIButton) {
    guard let sDate = startDateField?.textual content, !sDate.isEmpty, let eDate = endDateField?.textual content, !eDate.isEmpty else {
        validateDate(); return
    }
    if startSelectedDate > endSelectedDate {
        let invalid = localizedKey(key: "invalid.date")
        self.displayMessage(title: "", message: invalid, actions: [MessageAction.okAction()])
        return
    }
    if let val = segementControl?.isSelected, val == true {
        if let selectedSegment = segementControl?.selectedSegmentIndex {
            confirmDates = dates?[selectedSegment]
        }
    } else {
        guard let startText = startDateField?.textual content, let endText = endDateField?.textual content else {
            return
        }
        let startVal = DateUtil.convert(filledDate: startText, fromFormat: slash, intoFormat: sprint)
        let endVal = DateUtil.convert(filledDate: endText, fromFormat: slash, intoFormat: sprint)

        confirmDates = Dates(filterId: -1, title: "", begin: startVal, finish: endVal, mobileName: "")
        output.dismissView(view: self)
        return
    }
    output.dismissView(view: self)
}

@IBAction func onchangeDateSegment(_ sender: UISegmentedControl) {
    self.view.endEditing(true)
    segementControl?.isSelected = true
    let index = sender.selectedSegmentIndex
    if let dateValue = dates?[index] {
        startDateField?.textual content = DateUtil.convert(filledDate: dateValue.begin, fromFormat: sprint, intoFormat: slash)
        endDateField?.textual content = DateUtil.convert(filledDate: dateValue.finish, fromFormat: sprint, intoFormat: slash)
    }

}

personal func localizedKey(key: String) -> String {
    return NSLocalizedString(key, tableName: "DateFilter", remark: "")
}

@IBAction func onclickCrossButton(_ sender: UIButton) {
    output.dismissView(view: self)
}

personal func setSegmentControlContents(dates: [Dates], confirmDates: Dates?) {

    var objects = [String]()
    dates.forEach({objects.append($0.mobileName)})
    let segmentController = UISegmentedControl(objects: objects)
    segmentView?.addSubview(segmentController)
    segmentController.addTarget(self, motion: #selector(onchangeDateSegment), for: .valueChanged)
    segmentController.autoPinEdge(toSuperviewEdge: .prime)
    segmentController.autoPinEdge(toSuperviewEdge: .main)
    segmentController.autoPinEdge(toSuperviewEdge: .trailing)
    segmentController.autoPinEdge(toSuperviewEdge: .backside)
    segmentController.tintColor = UIColor.clear
    segmentController.layer.borderColor = UIColor.clear.cgColor
    segmentController.setTitleTextAttributes(self.look?.selectedDateFont, for: .chosen)
    segmentController.setTitleTextAttributes(self.look?.unSelectedDateFont, for: .regular)
    segementControl = segmentController
    if dates.accommodates(the place: {$0.mobileName == confirmDates?.mobileName}) {
        if let index = dates.firstIndex(the place: {$0.mobileName == confirmDates?.mobileName}) {
            segmentController.selectedSegmentIndex = index
            segementControl?.isSelected = true
        }
    }
}

personal func setViewAppearance(look: DateFilterAppearance) {
    startDateField?.configureAppearance(look.textAppearance, fieldAppearanceType: .dropDown)
    startDateField?.borderedEdges = BorderedEdge.all
    startDateField?.delegate = self
    startDateField?.placeholder = localizedKey(key: "from")

    endDateField?.configureAppearance(look.textAppearance, fieldAppearanceType: .dropDown)
    endDateField?.borderedEdges = BorderedEdge.all
    endDateField?.delegate = self
    endDateField?.placeholder = localizedKey(key: "to")

    mainButton?.configureAppearance(look.mainButtonAppearance, title: localizedKey(key: "mainButton.title"))

    startLabel?.configureAppearance(look.formLabel)
    endLabel?.configureAppearance(look.formLabel)
        output.confirmDates = confirmDates
    let begin = confirmDates?.begin ?? "", finish = confirmDates?.finish ?? ""
    startDateField?.textual content = DateUtil.convert(filledDate: begin, fromFormat: sprint, intoFormat: slash)
    endDateField?.textual content = DateUtil.convert(filledDate: finish, fromFormat: sprint, intoFormat: slash)
    if let knowledge = dates {
        setSegmentControlContents(dates: knowledge, confirmDates: confirmDates)
    }
}

@objc func handleStartDatePicker(sender: UIDatePicker) {
    segementControl?.isSelected = false
    segementControl?.selectedSegmentIndex = -1
    startSelectedDate = sender.date
    self.startDateField?.textual content = DateUtil.convertStringFromDate(date: sender.date)
}

@objc func handleEndDatePicker(sender: UIDatePicker) {
    segementControl?.isSelected = false
    segementControl?.selectedSegmentIndex = -1
    endSelectedDate = sender.date
    self.endDateField?.textual content = DateUtil.convertStringFromDate(date: sender.date)
}
}

extension DateFilterViewController: UITextFieldDelegate {
    func textFieldDidBeginEditing(_ textField: UITextField) {
        callDatePicker(textField: textField)
    }
}

The Difficulty is in beneath movement:

  1. I’ve chosen startDate as “07/23/24” (i.e twenty third July 2024)
  2. I’ve chosen endDate as “07/23/24” (i.e. twenty third July 2024)

works tremendous no concern.

then
3. I’ve chosen endDate as “07/24/24” (i.e. twenty fourth July 2024)
It shows Validation Popup as “StartDate can’t be larger than EndDate”
Code :

if startSelectedDate > endSelectedDate {
        let invalid = localizedKey(key: "invalid.date")
        self.displayMessage(title: "", message: invalid, actions: [MessageAction.okAction()])
        return
    }

inside onClickConfirmButton button.

On this case popup shouldn’t be show as It’s setting 07/23/23 on startDate Subject and 07/24/24 on endDate Filed.

The problem is in startSelectedDate and endSelectedDate Values.
I get values as beneath:

startSelectedDate : 2024-10-14 13:51:13 +0000

endSelectedDate : 2024-07-23 18:30:00 +0000

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles