I'm trying to update two buttons with datepicker. Button startDate et endDate. I don't how can I update these butttons with differents datepicker.
Maybe with handler ?
user story : the user click on startDat datepicker is displaying, user choose any date or time, then click on endDate and same action.
EDIT:
class ViewController: UIViewController {
#IBOutlet weak var dateTextField: UITextField!
#IBOutlet weak var dateTextLabel: UILabel!
var whoTriggeredPickerView: UIButton?
#IBOutlet weak var startDateTextButton : UIButton!
#IBOutlet weak var endDateTextButton : UIButton!
#IBOutlet weak var datePick : UIDatePicker!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func donePressed(_ sender: UIBarButtonItem) {
dateTextField.resignFirstResponder()
dateTextLabel.resignFirstResponder()
startDateTextButton.resignFirstResponder()
endDateTextButton.resignFirstResponder()
}
func donePressedButton(_ sender :UIButton){
startDateTextButton.resignFirstResponder()
endDateTextButton.resignFirstResponder()
}
func tappedToolBarBtn(_ sender: UIBarButtonItem) {
let dateformatter = DateFormatter()
startDateTextButton.setTitle(dateformatter.string(from: Date()), for: .normal)
endDateTextButton.setTitle(dateformatter.string(from: Date()), for: .normal)
startDateTextButton.resignFirstResponder()
endDateTextButton.resignFirstResponder()
}
func closeDatePicker(){
self.view.endEditing(true)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
closeDatePicker()
}
#IBAction func BtnClicked(sender: UIButton) {
let datePickerView: UIDatePicker = UIDatePicker()
datePickerView.datePickerMode = UIDatePickerMode.date
//sender.inputView = datePickerView
self.view.addSubview(datePickerView)
datePickerView.addTarget(self, action: #selector(ViewController.datePickerValueChanged), for: UIControlEvents.valueChanged)
self.whoTriggeredPickerView = sender
}
func datePickerValueChanged(_ sender: UIDatePicker) {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = DateFormatter.Style.medium
dateFormatter.timeStyle = DateFormatter.Style.none
//dateTextField.text = dateFormatter.string(from: sender.date)
if self.whoTriggeredPickerView == startDateTextButton {
// set startDateBtn title
startDateTextButton.setTitle(dateFormatter.string(from: Date()), for: .normal)
}else if self.whoTriggeredPickerView == endDateTextButton {
// set endDateBtn title
endDateTextButton.setTitle(dateFormatter.string(from: Date()), for: .normal)
}
}
}
For your question:
You can create a tmp variable to record picker is triggered by which button. Then you can decide which button's title you want to set.
//In your view controller:
var whoTriggeredPickerView: UIButton?
//In your BtnClicked function:
self.whoTriggeredPickerView = sender
//Then in datePickerValueChanged function:
if self.whoTriggeredPickerView == StartDateButton {
// set startDateBtn title
}else if self.whoTriggerPickerView == endDateButton {
// set endDateBtn title
}
Some suggestions:
always lowercase the instance name, you are using DatePick as the instance name of UIDatePicker, instead, you should name it as datePicker; for function names as well.
for your case you can use two textfields instead of buttons.
let datePicker = UIDatePicker()
datePicker.addTarget(self, action: #selector(dateChanged), for: .valueChanged)
startDateTextField.inputView = datePicler
endDateTextField.inputView = datePicker
Related
I want to implement a function that activates the button when the text field and date picker are set.
The value of the date picker goes to the label, and I checked the button by changing the label value.
However, among other functions that I have implemented, if the navigation is popped using a singleton object and the value is saved when it comes back, if the button is checked with a label change, the button is not activated because it is duplicated with the singleton, or even if only the phone number is set. It happens that the button is activated.
So, rather than changing the label, is there a way to catch it when the date picker itself changes the value?
import UIKit
class ThirdViewController: UIViewController {
lazy var dateFormatter: DateFormatter = {
let date = DateFormatter()
date.dateStyle = .medium
date.timeStyle = .none
return date
}()
#IBOutlet weak var dateLabel: UILabel!
#IBOutlet weak var numberTextField: UITextField!
#IBOutlet weak var datePicker: UIDatePicker!
#IBOutlet weak var signUpButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
numberTextField.addTarget(self, action: #selector(editingChanged(_:)), for: .editingChanged)
numberTextField.text = UserInformation.userInformationSingleton.userNumber
dateLabel.text = UserInformation.userInformationSingleton.dateLabel
}
#objc func editingChanged(_ textField: UITextField) {
if textField.text?.count == 1 {
if textField.text?.first == " " {
textField.text = ""
return
}
}
toggleButton()
}
func toggleButton() {
guard
let textField = numberTextField.text, !textField.isEmpty,
dateLabel.text != ""
else {
signUpButton.isEnabled = false
return
}
signUpButton.isEnabled = true
}
#IBAction func datePickerValueChanged(_ sender: UIDatePicker) {
dateLabel.text = dateFormatter.string(from: sender.date)
toggleButton()
}
#IBAction func cancelButton(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
UserInformation.userInformationSingleton.userID = nil
UserInformation.userInformationSingleton.userNumber = nil
UserInformation.userInformationSingleton.dateLabel = nil
}
#IBAction func tappedPreviousButton(_ sender: UIButton) {
self.navigationController?.popViewController(animated: true)
}
#IBAction func tappedSignUpButton(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}
}
https://i.stack.imgur.com/a1GVc.png
thanks for reading!!
solved the problem!
func toggleButton() {
guard
let textField = numberTextField.text, !textField.isEmpty,
let label = dateLabel.text, !label.isEmpty
else {
signUpButton.isEnabled = false
return
}
signUpButton.isEnabled = true
}
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:
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?
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.
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)
}
}
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)
}
I'm making a To-Do app and I want the value of the date picker as saved by the user into a variable so that I can print that variable in a tableView.
This is my datePicker code:
#IBOutlet weak var datePicker: UIDatePicker!
override func viewDidLoad() {
super.viewDidLoad()
datePicker.minimumDate = Date()
datePicker.locale = Locale.current
datePicker.setValue(UIColor.gray, forKeyPath: "textColor")
}
You can add a specific target to you Picker in order to get a new value.
For example :
#IBOutlet weak var datePicker: UIDatePicker!
var selectedDate : Date?
override func viewDidLoad() {
super.viewDidLoad()
self.datePicker.addTarget(self, action: #selector(self.storeSelectedRow), for: UIControlEvents.valueChanged)
}
func storeSelectedRow(){
self.selectedDate = self.datePicker.date
}
OR
With the storyboard:
As you add you pickerView as a #IBOutlet you can add a #IBAction to your view controller and then get the date of your picker and store it to a variable.
Please see this example that pass the Picker Value to another ViewController
https://drive.google.com/file/d/0B2RAeG6eqtvCbWp1VE5IZ0E2Vkk/view?usp=sharing
Add follow code in viewDidLoad.
datePicker.addTarget(self, action: "dateChanged:",
forControlEvents: UIControlEvents.ValueChanged)
Then get value in func dateChanged.
func dateChanged(datePicker : UIDatePicker){
let formatter = NSDateFormatter()
//formatter
formatter.dateFormat = "yyyy年MM月dd日 HH:mm:ss"
print(formatter.stringFromDate(datePicker.date))
//there you get your label first
//let label = ...
label.text = formatter.stringFromDate(datePicker.date)
}
I'm very new to all of this and I found some code that got me understanding some of this syntax. I'm trying to create a textfield that lets me type in a value that updates the stepper's value. The stepper currently works (updates the uitextfield) but when I change the value in the textfield it doesn't update the stepper's value, so when I click on the stepper, it reverts back to whatever value it was before I typed in a value... Can anyone tell me why the two functions STracksValueDidChange and CTrackValueDidChange have errors?
Here's my code so far:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var STracks: UITextField!
#IBOutlet weak var STracksStepper: UIStepper!
#IBOutlet weak var CTracks: UITextField!
#IBOutlet weak var CTrackStepper: UIStepper!
override func viewDidLoad() {
super.viewDidLoad()
STracksStepper.autorepeat = true
STracksStepper.maximumValue = 100.0
STracksStepper.minimumValue = 2.0
STracksStepper.stepValue = 2.0
print(STracksStepper.value)
STracks.text = "\(Int(STracksStepper.value))"
STracksStepper.addTarget(self, action: "SstepperValueDidChange:", forControlEvents: .ValueChanged)
STracks.addTarget(self, action: "STextValueDidChange:", forControlEvents: .ValueChanged)
CTrackStepper.autorepeat = true
CTrackStepper.maximumValue = 100.0
CTrackStepper.minimumValue = 2.0
CTrackStepper.stepValue = 2.0
print(CTrackStepper.value)
CTracks.text = "\(Int(CTrackStepper.value))"
CTrackStepper.addTarget(self, action: "CstepperValueDidChange:", forControlEvents: .ValueChanged)
CTracks.addTarget(self, action: "CTextValueDidChange:", forControlEvents: .ValueChanged)
}
//Steppers will update UITextFields
func SstepperValueDidChange(stepper: UIStepper) {
let stepperMapping: [UIStepper: UITextField] = [STracksStepper: STracks]
stepperMapping[stepper]!.text = "\(Int(stepper.value))"
}
func STracksValueDidChange(SText: UITextField) {
let STextMapping: [UITextField: UIStepper] = [STracks: STracksStepper]
STextMapping[SText]!.value = "(SText.text)"
}
func CstepperValueDidChange(stepper: UIStepper) {
let stepperMapping: [UIStepper: UITextField] = [CTrackStepper: CTracks]
stepperMapping[stepper]!.text = "\(Int(stepper.value))"
}
func CTrackValueDidChange(CText: UITextField) {
let CTextMapping: [UITextField: UIStepper] = [CTracks: CTrackStepper]
CTextMapping[CText]!.value = "(CText.text)"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Try something like this.
CTrackStepper.value = Double(Textfield.text)
I am not so sure what the mapping is in your code.
But i don't think you need it for changing the value.
Update, made a project my self:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textfield: UITextField!
#IBOutlet weak var stepper: UIStepper!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func stepperValueChanged(sender: UIStepper) {
textfield.text = String(sender.value)
}
#IBAction func valueChanged(sender: UITextField) {
if Double(sender.text!) != nil {
stepper.value = Double(sender.text!)!
}
}
}
For steppervaluechanged and valuechanged just drag from uistepper and textfield and choose action and change the Anyobject to Uistepper of Uitextfield.
Good luck :)
I have a DatePicker where the user selects time and date fields, the keyboard shows up first and then I have to click the textfield again for the Picker to appear. What I want is for the DatePicker to show up on the first try.
here is my code
#IBOutlet var dateField: UITextField! = UITextField()
#IBOutlet var timeField: UITextField! = UITextField()
#IBAction func userPickDate(sender: UITextField) {
var datePickerView : UIDatePicker = UIDatePicker()
datePickerView.datePickerMode = UIDatePickerMode.Date
sender.inputView = datePickerView
datePickerView.addTarget(self, action: Selector("handleDatePicker:"), forControlEvents: UIControlEvents.ValueChanged)
}
#IBAction func userPickTime(sender: UITextField) {
var datePickerView : UIDatePicker = UIDatePicker()
datePickerView.datePickerMode = UIDatePickerMode.Time
sender.inputView = datePickerView
datePickerView.addTarget(self, action: Selector("handleTimePicker:"), forControlEvents: UIControlEvents.ValueChanged)
}
func handleTimePicker(sender: UIDatePicker)
{
var timeFormatter = NSDateFormatter()
timeFormatter.timeStyle = .ShortStyle
timeField.text = timeFormatter.stringFromDate(sender.date)
}
func handleDatePicker(sender: UIDatePicker) {
var timeFormatter = NSDateFormatter()
timeFormatter.dateStyle = .MediumStyle
//timeFormatter.timeStyle = .ShortStyle
dateField.text = timeFormatter.stringFromDate(sender.date)
}
Discard the last answer. I understood whAT you are doing. Here is what I found: Placing the declaration of the UPickerView objects in the scope of the class rather than localized to the handler seemed to work. Here is the code. Note the addition of the resignFirstResponder().
import UIKit
class ViewController: UIViewController {
var datePickerView : UIDatePicker = UIDatePicker()
var timePickerView : UIDatePicker = UIDatePicker()
#IBOutlet weak var dateField: UITextField!
#IBOutlet weak var timeField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
datePickerView.datePickerMode = UIDatePickerMode.Date
dateField.inputView = datePickerView
datePickerView.addTarget(self, action: Selector("handleDatePicker:"), forControlEvents: UIControlEvents.ValueChanged)
handleDatePicker(datePickerView)
timePickerView.datePickerMode = UIDatePickerMode.Time
timeField.inputView = timePickerView
timePickerView.addTarget(self, action: Selector("handleTimePicker:"), forControlEvents: UIControlEvents.ValueChanged)
handleTimePicker(timePickerView)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func handleDatePicker(sender: UIDatePicker) {
var dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = .MediumStyle
//timeFormatter.timeStyle = .ShortStyle
dateField.text = dateFormatter.stringFromDate(sender.date)
dateField.resignFirstResponder()
}
func handleTimePicker(sender: UIDatePicker) {
var timeFormatter = NSDateFormatter()
timeFormatter.timeStyle = .ShortStyle
timeField.text = timeFormatter.stringFromDate(sender.date)
timeField.resignFirstResponder()
}
}
You need to place an action on your textField as such:
#IBAction func userDOBSelectedAction(sender: UITextField) {
userDOBTextField.resignFirstResponder()
}
This is an updated version of Syed's answer for Swift 2.2 & includes some formatting updates.
import UIKit
class ViewController: UIViewController {
var datePickerView : UIDatePicker = UIDatePicker()
var timePickerView : UIDatePicker = UIDatePicker()
#IBOutlet weak var dateField: UITextField!
#IBOutlet weak var timeField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
datePickerView.datePickerMode = .Date
dateField.inputView = datePickerView
datePickerView.addTarget(self, action: #selector(ViewController.handleDatePicker(_:)), forControlEvents: .ValueChanged)
handleDatePicker(datePickerView)
timePickerView.datePickerMode = .Time
timeField.inputView = timePickerView
timePickerView.addTarget(self, action: #selector(ViewController.handleTimePicker(_:)), forControlEvents: .ValueChanged)
handleTimePicker(timePickerView)
}
func handleDatePicker(sender: UIDatePicker) {
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = .MediumStyle
dateField.text = dateFormatter.stringFromDate(sender.date)
dateField.resignFirstResponder()
}
func handleTimePicker(sender: UIDatePicker) {
let timeFormatter = NSDateFormatter()
timeFormatter.timeStyle = .ShortStyle
timeField.text = timeFormatter.stringFromDate(sender.date)
timeField.resignFirstResponder()
}
}