2

I just begin to learn iOS dev, here I want to show a datePicker and get date from the user, but I don't know how to show a DataPicker from the bottom of screen. After searching, I found that: dataPicker can be activated by a textField simply by "myTextField.inputView = myDatepicker". I did that, but I faced questions:

  1. After activating the datePicker, the user is able to cut, paste the date shown in the textField. Is there some way to disable the selection of the content in the textField and also the editing menu?

  2. Instead of using a textField, if I want to use a UIButton/UILabel/cell to activate the dataPicker, How can I do that?(I mean how to show the DatePicker from the bottom. I found UIButton/UILabel/cell have no method .inputView like textField does)

It may simple, but really confused me, this is the first app I am trying to do. Any help is very much appreciated, especially in detail, in Swift. Thank you very much.

Hao
  • 105
  • 1
  • 8
  • You should use the UILabel in place of UITextFiled, it will solve your problem. – Satish Mavani Jan 04 '18 at 07:33
  • Possible duplicate of [Disable copy, paste in UITextfield is not working in iOS 9.x](https://stackoverflow.com/questions/37606969/disable-copy-paste-in-uitextfield-is-not-working-in-ios-9-x) – Prashant Tukadiya Jan 04 '18 at 07:35
  • Do you have a table view? Or there is just a button using which you want to show and hide the Pickerview? – Mahbub Morshed Jan 04 '18 at 08:39
  • You can try overriding this method - (BOOL)canPerformAction:(SEL)action withSender:(id)sender { if ((action == @selector(paste:)) || if (action == @selector(copy:))) return NO; return [super canPerformAction:action withSender:sender]; } – DGoogly Jan 04 '18 at 09:51
  • please see my question again, I just add descriptions, now it is clear. many misunderstood my meaning. thanks – Hao Jan 04 '18 at 10:25

2 Answers2

0

Way 1

Use a button to show the date and a button to show/ hide the datepicker embedded in a view.

class ViewController: UIViewController {

    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var datePicker: UIDatePicker!
    @IBOutlet weak var chooseDate: UIButton!

    @IBAction func toggleDatePicker(_ sender: Any) {
        datePicker.isHidden = !datePicker.isHidden
    }

    override func viewDidLoad() {
        dateLabel.text = stringFrom(date: Date())
        datePicker.isHidden = true
    }
}
extension ViewController: UIPickerViewDelegate {

    @IBAction func valueChanged() {
        dateLabel.text = stringFrom(date: datePicker.date)
    }

    private func stringFrom(date: Date) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd-MM-yyyy"
        return dateFormatter.string(from: datePicker.date)
    }
}

Way 2

Use a button to show the date and a button to show/ hide the datepicker from the bottom.

Just use the following protocol that I wrote:


protocol DatePickable: class {

    var textField: UITextField { get }
    var datePicker: UIDatePicker { get }

    var isDatePickerVisible: Bool { get set }
}


extension DatePickable {

    func prepareDatePickerFor(view: UIView, onChangeAction: Selector) {
        datePicker.datePickerMode = UIDatePickerMode.date
        datePicker.addTarget(self, action: onChangeAction, for: .valueChanged)

        textField.inputView = datePicker
        view.addSubview(textField)
    }

    func toggleDatePicker() {
        isDatePickerVisible ? hideDatePicker() : showDatePicker()
        isDatePickerVisible = !isDatePickerVisible
    }

    private func showDatePicker() {
        textField.becomeFirstResponder()
    }

    private func hideDatePicker() {
        textField.resignFirstResponder()
    }
}

How to use the protocol in you class:


class ViewController: UIViewController, DatePickable {

    // Required by Datepickable
    var isDatePickerVisible = false

    var textField: UITextField = UITextField()
    var datePicker: UIDatePicker = UIDatePicker()

    // IBOutlets
    @IBOutlet weak var dateLabel: UILabel!
    @IBOutlet weak var chooseDate: UIButton!

    override func viewDidLoad() {

        prepareDatePickerFor(view: view,
                             onChangeAction: #selector(ViewController.onDidChangeDate(_:)))

        dateLabel.text = stringFrom(date: Date())
    }

    @IBAction func toggleDatePickerVisibility(_ sender: Any) {
        toggleDatePicker()
    }

    @IBAction func onDidChangeDate(_ sender: Any) {
        dateLabel.text = stringFrom(date: datePicker.date)
    }

    private func stringFrom(date: Date) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "dd-MM-yyyy"
        return dateFormatter.string(from: datePicker.date)
    }
}

Mahbub Morshed
  • 915
  • 9
  • 20
  • Thank you, I can understand your answer. However it does not cover my confusion. What I do not understand is "How to show the datepicker"? (by using a textField, I can simply use 'myTextField.inputView = myDatepicker' to show it when taping the textField). So please give me some help about how to show the picker if I want the picker to come up from the bottom of screen(I know how to show a picker in a new pushed view, but I do not want to do like that). Thank you. – Hao Jan 04 '18 at 10:06
  • Don't forget to upvote and accept the answer if it is what you are looking for. :) – Mahbub Morshed Jan 04 '18 at 21:11
  • thanks @Mahbub, this is my first time to ask question, just voted. there is still a problem about your way 2. that is: the datePicker generated by textFiled will cover the home indicator. How can I solve this? I appreciated if you could help me about this. – Hao Jan 05 '18 at 02:46
0

So you have to add textfield delegate and then recognise the right textfield:

let datePicker = UIDatePicker()
func viewDidLoad() {
    super.viewDidLoad()
    txtDatePicker.delegate = self
}

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    if textField == txtDatePicker {
        showDatePicker()
    }
    return true
}

Then inside showDatePicker you will tell your picker what mode should it be as follows:

func showDatePicker() {
    //Formate Date
    datePicker.datePickerMode = .date
    // if you need a toolbar, here is a good place to define it
    // add datepicker to textField
    txtDatePicker.inputView = datePicker
}

Then in delegate function or toolbar selection you do as follows:

func donedatePicker() {
    //For date formate

    let formatter = DateFormatter()
    formatter.dateFormat = "dd/MM/yyyy"
    txtDatePicker.text = formatter.string(from: datePicker.date)

    self.view.endEditing(true)
}
arkmon
  • 121
  • 9
  • thx friend, but it may not my concern. In this way, the user is still able to cut, paste the date shown in the textField(this is my concern). I want to activate the date picker by other object such as UIButton/Label, but they have no method called .inputView like textField does. So I don't know how to do. Please tell me the reasonable way to activate the Datepicker, thanks – Hao Jan 04 '18 at 11:10
  • @Hao So if you still want to use the textfield so you have the inputview as bottom entry then i would try disabling user interaction to the text field and then ad transparent uibutton on top to trigger the date picker, could also play with gesture recogniser. These aren't ideal so i hope someone else have better idea. – arkmon Jan 04 '18 at 11:54