I've tried lots of numeric keyboard with done button, it's not found a correct answer in SWIFT 2.0.
You can add done button above keyboard using toolbar
override func viewDidLoad() {
super.viewDidLoad()
let tooBar: UIToolbar = UIToolbar()
tooBar.barStyle = UIBarStyle.BlackTranslucent
tooBar.items=[
UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: self, action: nil),
UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: "donePressed")]
tooBar.sizeToFit()
yourTextFeild.inputAccessoryView = tooBar
}
func donePressed () {
yourTextFeild.resignFirstResponder()
}
It will look like this
Without toolbar, I'd added the done button in the Return key place itself by the following steps,
Create a custom Return button as below
let mobilePadNextButton = UIButton(type: UIButtonType.custom)
In viewdidload, design it. Here I'm designing Next button as I need Next instead of Done.
mobilePadNextButton.setTitle("Next", for: UIControlState())//Set Done here
mobilePadNextButton.setTitleColor(UIColor.black, for: UIControlState())
mobilePadNextButton.frame = CGRect(x: 0, y: 163, width: 106, height: 53)
mobilePadNextButton.adjustsImageWhenHighlighted = false
mobilePadNextButton.addTarget(self, action: #selector(self.mobilePadNextAction(_:)), for: UIControlEvents.touchUpInside)
Add Keyboad notification
func textFieldDidBeginEditing(_ textField: UITextField) {
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
}
func keyboardWillShow(notification:NSNotification){
if mobileNoTxtFld.isFirstResponder
{
DispatchQueue.main.async { () -> Void in
self.mobilePadNextButton.isHidden = false
let keyBoardWindow = UIApplication.shared.windows.last
self.mobilePadNextButton.frame = CGRect(x: 0, y: (keyBoardWindow?.frame.size.height)!-53, width: 106, height: 53)
keyBoardWindow?.addSubview(self.mobilePadNextButton)
keyBoardWindow?.bringSubview(toFront: self.mobilePadNextButton)
UIView.animate(withDuration: (((notification.userInfo! as NSDictionary).object(forKey: UIKeyboardAnimationCurveUserInfoKey) as AnyObject).doubleValue)!, delay: 0, options: UIViewAnimationOptions.curveEaseIn, animations: { () -> Void in
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: 0)
}, completion: { (complete) -> Void in
print("Complete")
})
}
}
else
{
self.mobilePadNextButton.isHidden = true
}
}
Here, you can do the done actions
func mobilePadNextAction(_ sender : UIButton){
//Click action
}
The UI will looks like below,
I referred this Git Code
Related
I tried to add a toolbar for my UITextFiled, the keyboard is set to numpad. It is working but the button is not showing. I created an extension for my UITextfield
extension UITextField {
/// Adding a done button on the keyboard
func addDoneButtonOnKeyboard() {
let doneToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
doneToolbar.barStyle = .default
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let done = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))
let items = [flexSpace, done]
doneToolbar.items = items
doneToolbar.sizeToFit()
self.inputAccessoryView = doneToolbar
}
/// Done button callback
#objc func doneButtonAction() {
self.resignFirstResponder()
}
}
and then I am calling this extension like this
private lazy var fromInputField: CoinpassInput = {
let input = CoinpassInput()
input.keyboardType = .decimalPad
input.addTarget(self, action: #selector(fromInputFieldDidChange), for: .editingChanged)
input.addDoneButtonOnKeyboard()
return input
}()
the toolbar is showing and working but the 'done; button is not showing. If I click on the right corner of the toolbar. the keyboard will hide. I dont know what I am missing why the button is not showing.
Try this code, with slight modifications:
func addDoneButtonOnKeyboard() {
let doneToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
doneToolbar.barStyle = .default
doneToolbar.barTintColor = .red
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let done = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))
done.tintColor = .yellow
doneToolbar.setItems([flexSpace,done], animated: false)
doneToolbar.isUserInteractionEnabled = true
self.inputAccessoryView = doneToolbar
}
In my app, I have a button which when clicked should display time picker with toolbar on it. Most of examples I saw added toolbar as an inputAccessoryView on text field, but in my case I don't have a text field.
So, I created a custom view which has date time picker and toolbar and I am adding that view as a subview to my controller's view, but I don't see the custom view on the app.
Below is the controller code for button clicked :
func buttonClicked(date: Date) {
let timePicker = EditTimeHelper.createTimePickerAndToolbar(displayDate: date)
self.view.addSubview(timePicker)
}
Code for custom view in separate EditTimeHelper class:
static func createTimePickerAndToolbar(displayDate: Date) -> UIView {
let pickerView = UIView(frame: CGRect(x: 0, y: UIScreen.main.bounds.height - 300, width: UIScreen.main.bounds.width, height: 300))
let timePicker = createTimePicker(displayDate: displayDate)
pickerView.addSubview(timePicker)
let toolbar = createUIToolBar()
pickerView.addSubview(toolbar)
return pickerView
}
static func createTimePicker(displayDate: Date) -> UIDatePicker {
let timePicker:UIDatePicker = UIDatePicker()
timePicker.datePickerMode = UIDatePicker.Mode.time
timePicker.date = displayDate
timePicker.minuteInterval = 15
if #available(iOS 13.4, *) {
timePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions where time picker is wheels style by default.
}
timePicker.addTarget(self, action: #selector(timeChanged(_:)), for: UIControl.Event.valueChanged)
timePicker.backgroundColor = .white
timePicker.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 200, width: UIScreen.main.bounds.width, height: 200)
return timePicker
}
private static func createUIToolBar() -> UIToolbar {
let pickerToolbar = UIToolbar()
pickerToolbar.autoresizingMask = .flexibleHeight
//customize the toolbar
pickerToolbar.barStyle = .default
pickerToolbar.barTintColor = UIColor.black
pickerToolbar.backgroundColor = UIColor.white
pickerToolbar.isTranslucent = false
pickerToolbar.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 300, width: UIScreen.main.bounds.width, height: 100)
// add buttons
let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelBtnClicked(_:)))
cancelButton.tintColor = UIColor.white
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneBtnClicked(_:)))
doneButton.tintColor = UIColor.white
//add the items to the toolbar
pickerToolbar.items = [cancelButton, flexSpace, doneButton]
return pickerToolbar
}
#objc func timeChanged(_ sender: UIDatePicker) {
}
#objc func cancelBtnClicked(_ button: UIBarButtonItem?) {
}
#objc func doneBtnClicked(_ button: UIBarButtonItem?) {
}
Any idea what am I doing wrong and not seeing custom view?
If I call EditTimeHelper.createTimePicker(displatDate: date), then I see the time picker, but I want to add toolbar on top of it.
When I debug this code, I do see time picker and toolbar as custom view's subviews, but I just don't see them on the app.
The reason why you can't see the picker and the tool bar is because you have positioned the time picker and the tool bar incorrectly. Notice these two lines:
timePicker.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 200, width: UIScreen.main.bounds.width, height: 200)
// and
pickerToolbar.frame = CGRect(x: 0, y: UIScreen.main.bounds.height - 300, width: UIScreen.main.bounds.width, height: 100)
Since these are subviews of the pickerView, the coordinates are relative to the top left corner of pickerView, not the top left corner of the screen. You should instead do
timePicker.frame = CGRect(x: 0, y: 100, width: UIScreen.main.bounds.width, height: 200)
// and
pickerToolbar.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 100)
Now you should see the tool bar and the time picker.
There are other problems with your code, however. First, timeChanged, cancelBtnClicked and doneBtnClicked won't be called. You have added self as the target for the bar button items and the picker, but since you are in a static method, self refers to the class itself. When the user presses the done button, it would try to call a method called doneBtnClicked on the class, rather than a particular instance. But the class doesn't have such a method! The doneBtnClicked you have declared is an instance method, available on instances only.
Second, you are giving these views fixed positions. This means that the layout will look very weird when the user rotates the screen. Just use AutoLayout!
You can make timeChanged, cancelBtnClicked and doneBtnClicked all static too, but a much better way is to just create a custom UIView subclass. Here is an example, as a starting point:
class TimePickerToolBarView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
private func commonInit() {
let timePicker = createTimePicker()
addSubview(timePicker)
let toolBar = createUIToolBar()
addSubview(toolBar)
timePicker.translatesAutoresizingMaskIntoConstraints = false
toolBar.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
toolBar.heightAnchor.constraint(equalToConstant: 44),
toolBar.topAnchor.constraint(equalTo: topAnchor),
toolBar.leftAnchor.constraint(equalTo: leftAnchor),
toolBar.rightAnchor.constraint(equalTo: rightAnchor),
timePicker.leftAnchor.constraint(equalTo: leftAnchor),
timePicker.rightAnchor.constraint(equalTo: rightAnchor),
timePicker.bottomAnchor.constraint(equalTo: bottomAnchor),
timePicker.topAnchor.constraint(equalTo: toolBar.bottomAnchor),
])
}
private func createTimePicker() -> UIDatePicker {
let timePicker:UIDatePicker = UIDatePicker(frame: .zero)
timePicker.datePickerMode = UIDatePicker.Mode.time
timePicker.minuteInterval = 15
if #available(iOS 13.4, *) {
timePicker.preferredDatePickerStyle = .wheels
} else {
// Fallback on earlier versions where time picker is wheels style by default.
}
timePicker.addTarget(self, action: #selector(timeChanged(_:)), for: UIControl.Event.valueChanged)
timePicker.backgroundColor = .white
return timePicker
}
private func createUIToolBar() -> UIToolbar {
let pickerToolbar = UIToolbar(frame: .zero)
//customize the toolbar
pickerToolbar.barStyle = .default
pickerToolbar.barTintColor = UIColor.black
pickerToolbar.backgroundColor = UIColor.white
pickerToolbar.isTranslucent = false
// add buttons
let cancelButton = UIBarButtonItem(barButtonSystemItem: .cancel, target: self, action: #selector(cancelBtnClicked(_:)))
cancelButton.tintColor = UIColor.white
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneBtnClicked(_:)))
doneButton.tintColor = UIColor.white
//add the items to the toolbar
pickerToolbar.items = [cancelButton, flexSpace, doneButton]
return pickerToolbar
}
#objc func timeChanged(_ sender: UIDatePicker) {
}
#objc func cancelBtnClicked(_ button: UIBarButtonItem?) {
}
#objc func doneBtnClicked(_ button: UIBarButtonItem?) {
}
}
I would like to implement a done toolbar above the numpad keyboard when the textfield is tapped however the toolbar is not showing up for some reason.
The following code sample has been used:
extension UITextField{
#IBInspectable var doneAccessory: Bool{
get{
return self.doneAccessory
}
set (hasDone) {
if hasDone{
addDoneButtonOnKeyboard()
}
}
}
func addDoneButtonOnKeyboard()
{
let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
doneToolbar.barStyle = .default
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: .done, target: self, action: #selector(self.doneButtonAction))
let items = [flexSpace, done]
doneToolbar.items = items
doneToolbar.sizeToFit()
self.inputAccessoryView = doneToolbar
}
#objc func doneButtonAction()
{
self.resignFirstResponder()
}
}
Make sure in your storyboard, TextField's property inspector doneAccessory property is set to ON
and O/P looks like
class MainVC: UIViewController {
var datasourceForUsers :UserPicker!
var userPicker :UIPickerView!
var toolBar: UIToolbar!
override func viewDidLoad() {
super.viewDidLoad()
userPicker = UIPickerView()
toolBar = UIToolbar()
datasourceForUsers = UserPicker()
}
#IBAction func onMoreTapped(){
NotificationCenter.default.post(name: NSNotification.Name("ToggleSideMenu"), object: nil)
}
#IBAction func showRegisteredUsers(_ sender: Any) {
createUserPicker()
configureToolBar(toolBar)
}
func createUserPicker() {
userPicker.dataSource = datasourceForUsers
userPicker.delegate = datasourceForUsers
//Customizations
userPicker.backgroundColor = .black
userPicker.frame = CGRect.init(x: 0.0, y: UIScreen.main.bounds.size.height - 300, width: UIScreen.main.bounds.size.width, height: 300)
self.view.addSubview(userPicker)
}
func configureToolBar(_ toolBar:UIToolbar ){
toolBar.sizeToFit()
toolBar.barTintColor = .black
toolBar.tintColor = .white
let doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(MainVC.dismissKeyboard))
toolBar.setItems([doneButton], animated: false)
toolBar.isUserInteractionEnabled = true
toolBar.frame = CGRect.init(x: 0.0, y: UIScreen.main.bounds.size.height - 300, width: UIScreen.main.bounds.size.width, height: 50)
self.view.addSubview(toolBar)
}
override func viewWillAppear(_ animated: Bool) {
userPicker.reloadAllComponents()
toolBar.reloadInputViews()
}
#objc func cancelDatePicker(){
self.view.endEditing(true)
}
#objc func dismissKeyboard() {
self.resignFirstResponder()
}
}
I used above code to show some data on UIPickerView .It works fine.But When I change the datasource(Add new Data) where the data is stored it does not reflect on the UI picker.In order to do that I have to run the application again.Second thing is I couldn't close the UI picker with transition.
I have read the post on how to create these buttons but they use a tag system to identify the textFields. I am using a prototype cell to create my textFields
func addDoneButtonOnKeyboard(_ hasNextBtn: Bool = false) -> UIView {
let doneToolbar: UIToolbar = UIToolbar(frame: CGRect(x: 0, y: 163, width: 106, height: 53))
doneToolbar.barStyle = UIBarStyle.default
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let done: UIBarButtonItem = UIBarButtonItem(title: "Done",
style: UIBarButtonItemStyle.done,
target: self,
action: #selector(doneAction))
let next: UIBarButtonItem = UIBarButtonItem(title: "Next",
style: .plain,
target: self,
action: #selector(nextAction))
var items = [UIBarButtonItem]()
items.append(flexSpace)
if hasNextBtn {
items.append(next)
} else {
items.append(done)
}
doneToolbar.items = items
doneToolbar.sizeToFit()
return doneToolbar
}
#objc func doneAction() {
self.view.endEditing(true)
}
#objc func nextAction(_ textField: UITextField) -> Bool {
let indexPath = IndexPath(row: index, section: 2)
// if textField.returnKeyType == .next {
if textField.inputAccessoryView == next as! UIView? {
guard let table = tableView, let ip = indexPath,
let cell = table.cellForRow(at: IndexPath(row: ip.row + 1, section: ip.section)) as? FormFieldTableViewCell
else { return true }
return cell.becomeFirstResponder()
}
return true
}
You can change Change button Type on Keyboard as follows,
// Assign in your cellForRowAtIndexPath method
yourTextField.returnKeyType = .Next
txtField.returnKeyType = .Done
txtField.returnKeyType = .Go
And Many more from below,
case Default
case Go
case Google
case Join
case Next
case Route
case Search
case Send
case Yahoo
case Done
case EmergencyCall
You can after handle action as desire in UITextFieldDelegate.