Toolbar with "Previous" and "Next" for Keyboard inputAccessoryView - ios

I've been trying to implement this toolbar, where only the 'Next' button is enabled when the top textField is the firstResponder and only the 'Previous' button is enabled when the bottom textField is the firstResponder.
It kind of works, but what keeps happening is I need to tap the 'Previous'/'Next' buttons twice each time to enable/disable the opposing button.
Am I missing something in the responder chain that's making this happen?
Here's my code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.topText becomeFirstResponder];
}
- (UIToolbar *)keyboardToolBar {
UIToolbar *toolbar = [[UIToolbar alloc] init];
[toolbar setBarStyle:UIBarStyleBlackTranslucent];
[toolbar sizeToFit];
UISegmentedControl *segControl = [[UISegmentedControl alloc] initWithItems:#[#"Previous", #"Next"]];
[segControl setSegmentedControlStyle:UISegmentedControlStyleBar];
segControl.momentary = YES;
segControl.highlighted = YES;
[segControl addTarget:self action:#selector(changeRow:) forControlEvents:(UIControlEventValueChanged)];
[segControl setEnabled:NO forSegmentAtIndex:0];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] initWithCustomView:segControl];
NSArray *itemsArray = #[nextButton];
[toolbar setItems:itemsArray];
return toolbar;
}
- (void)changeRow:(id)sender {
int idx = [sender selectedSegmentIndex];
if (idx == 1) {
[sender setEnabled:NO forSegmentAtIndex:1];
[sender setEnabled:YES forSegmentAtIndex:0];
self.topText.text = #"Top one";
[self.bottomText becomeFirstResponder];
}
else {
[sender setEnabled:NO forSegmentAtIndex:0];
[sender setEnabled:YES forSegmentAtIndex:1];
self.bottomText.text =#"Bottom one";
[self.topText becomeFirstResponder];
}
}
-(void)textFieldDidBeginEditing:(UITextField *)textField {
if (!textField.inputAccessoryView) {
textField.inputAccessoryView = [self keyboardToolBar];
}
}

Here is a UIViewController extension that I use whenever I need a group of UITextFields to provide navigation via input accessory. No need to use UITextField delegation with this approach, and adding the behavior to multiple forms becomes a single-liner. Also supports the 'Done' button to dismiss.
extension UIViewController {
func addInputAccessoryForTextFields(textFields: [UITextField], dismissable: Bool = true, previousNextable: Bool = false) {
for (index, textField) in textFields.enumerated() {
let toolbar: UIToolbar = UIToolbar()
toolbar.sizeToFit()
var items = [UIBarButtonItem]()
if previousNextable {
let previousButton = UIBarButtonItem(image: UIImage(named: "Backward Arrow"), style: .plain, target: nil, action: nil)
previousButton.width = 30
if textField == textFields.first {
previousButton.isEnabled = false
} else {
previousButton.target = textFields[index - 1]
previousButton.action = #selector(UITextField.becomeFirstResponder)
}
let nextButton = UIBarButtonItem(image: UIImage(named: "Forward Arrow"), style: .plain, target: nil, action: nil)
nextButton.width = 30
if textField == textFields.last {
nextButton.isEnabled = false
} else {
nextButton.target = textFields[index + 1]
nextButton.action = #selector(UITextField.becomeFirstResponder)
}
items.append(contentsOf: [previousButton, nextButton])
}
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: view, action: #selector(UIView.endEditing))
items.append(contentsOf: [spacer, doneButton])
toolbar.setItems(items, animated: false)
textField.inputAccessoryView = toolbar
}
}
}
example:
let field1 = UITextField()
let field2 = UITextField()
addInputAccessoryForTextFields([field1, field2], dismissable: true, previousNextable: true)
Here's a reasonable arrow icon.

Swift:
lazy var inputToolbar: UIToolbar = {
var toolbar = UIToolbar()
toolbar.barStyle = .default
toolbar.translucent = true
toolbar.sizeToFit()
var doneButton = UIBarButtonItem(title: "Done", style: .bordered, target: self, action: "inputToolbarDonePressed")
var flexibleSpaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
var fixedSpaceButton = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
var nextButton = UIBarButtonItem(image: UIImage(named: "keyboardPreviousButton"), style: .bordered, target: self, action: "keyboardNextButton")
nextButton.width = 50.0
var previousButton = UIBarButtonItem(image: UIImage(named: "keyboardNextButton"), style: .Bordered, target: self, action: "keyboardPreviousButton")
toolbar.setItems([fixedSpaceButton, nextButton, fixedSpaceButton, previousButton, flexibleSpaceButton, doneButton], animated: false)
toolbar.userInteractionEnabled = true
return toolbar
}()
In UITextFieldDelegate
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
textField.inputAccessoryView = inputToolbar
return true
}

Okay, after looking at the brilliant BSKeyboardControls, I tried implementing the enabling and disabling of the segmented control in textFieldDidBeginEditing, instead of where my #selector was. I also introduced a variable for the segmented control.
It works now.
Here's the amended code snippet:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.topText becomeFirstResponder];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (UIToolbar *)keyboardToolBar {
UIToolbar *toolbar = [[UIToolbar alloc] init];
[toolbar setBarStyle:UIBarStyleBlackTranslucent];
[toolbar sizeToFit];
self.segControl = [[UISegmentedControl alloc] initWithItems:#[#"Previous", #"Next"]];
[self.segControl setSegmentedControlStyle:UISegmentedControlStyleBar];
self.segControl.momentary = YES;
[self.segControl addTarget:self action:#selector(changeRow:) forControlEvents:(UIControlEventValueChanged)];
[self.segControl setEnabled:NO forSegmentAtIndex:0];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] initWithCustomView:self.segControl];
NSArray *itemsArray = #[nextButton];
[toolbar setItems:itemsArray];
return toolbar;
}
- (void)changeRow:(id)sender {
int idx = [sender selectedSegmentIndex];
if (idx) {
self.topText.text = #"Top one";
[self.bottomText becomeFirstResponder];
}
else {
self.bottomText.text =#"Bottom one";
[self.topText becomeFirstResponder];
}
}
-(void)textFieldDidBeginEditing:(UITextField *)textField {
if (!textField.inputAccessoryView) {
textField.inputAccessoryView = [self keyboardToolBar];
}
if (textField.tag) {
[self.segControl setEnabled:NO forSegmentAtIndex:1];
[self.segControl setEnabled:YES forSegmentAtIndex:0];
}
}

My suggestion here is "don't reinvent the wheel".
Having Prev and Next button over a keyboard for switching between UITextViews is so common that you can find many good implementations ready to use.
Check out BSKeyboardControl, for instance.

Updated for Swift 3.0
lazy var inputToolbar: UIToolbar = {
var toolbar = UIToolbar()
toolbar.barStyle = .default
toolbar.isTranslucent = true
toolbar.sizeToFit()
var doneButton = UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(ContactViewController.inputToolbarDonePressed))
var flexibleSpaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
var fixedSpaceButton = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
var nextButton = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(ContactViewController.keyboardNextButton))
var previousButton = UIBarButtonItem(title: "Previous", style: .plain, target: self, action: #selector(ContactViewController.keyboardPreviousButton))
toolbar.setItems([fixedSpaceButton, previousButton, fixedSpaceButton, nextButton, flexibleSpaceButton, doneButton], animated: false)
toolbar.isUserInteractionEnabled = true
return toolbar
}()
And then:
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
textField.inputAccessoryView = inputToolbar
return true
}
Remember to change thange "ContactViewController" to the name of your View Controller.

You can also try the pod UITextField-Navigation:
pod 'UITextField-Navigation'
It adds two lazy-loaded properties nextTextField and previousTextField to any UITextField. All you need is to specify the nextTextField either on the interface builder or programmatically, and the toolbar is added to the keyboard for you.
Programmatically:
import UITextField_Navigation
let textField1 = UITextField()
let textField2 = UITextField()
textField1.nextTextField = textField2
assert(textField2 == textField1.nextTextField)
assert(textField1 == textField2.previousTextField)
On the Interface Builder:

Try this :-
- (void)viewDidLoad
{
[super viewDidLoad];
[self.topText becomeFirstResponder];
}
- (UIToolbar *)keyboardToolBar {
UIToolbar *toolbar = [[UIToolbar alloc] init];
[toolbar setBarStyle:UIBarStyleBlackTranslucent];
[toolbar sizeToFit];
UISegmentedControl *segControl = [[UISegmentedControl alloc] initWithItems:#[#"Previous", #"Next"]];
[segControl setSegmentedControlStyle:UISegmentedControlStyleBar];
segControl.momentary = YES;
segControl.highlighted = YES;
[segControl addTarget:self action:#selector(changeRow:) forControlEvents:(UIControlEventValueChanged)];
[segControl setEnabled:NO forSegmentAtIndex:0];
UIBarButtonItem *nextButton = [[UIBarButtonItem alloc] initWithCustomView:segControl];
NSArray *itemsArray = #[nextButton];
[toolbar setItems:itemsArray];
int idx = [sender selectedSegmentIndex];
if (idx == 1) {
[sender setEnabled:NO forSegmentAtIndex:1];
}
else {
[sender setEnabled:NO forSegmentAtIndex:0];
}
return toolbar;
}
- (void)changeRow:(id)sender {
int idx = [sender selectedSegmentIndex];
if (idx == 1) {
self.topText.text = #"Top one";
[self.bottomText becomeFirstResponder];
}
else {
self.bottomText.text =#"Bottom one";
[self.topText becomeFirstResponder];
}
}
-(void)textFieldDidBeginEditing:(UITextField *)textField {
if (!textField.inputAccessoryView) {
textField.inputAccessoryView = [self keyboardToolBar];
}
}
you dont need to enable other item as they reinitialise every time when keyboard changes ....

Related

How to add done button on keyboard on top of keyboard in IOS?

I want to add the Done button on the top of keyboard on right side in iOS for a textView.Please tell me how can i do that?
I want to achieve something similar to the above keyboard
Hope this help :)
UIToolbar* keyboardToolbar = [[UIToolbar alloc] init];
[keyboardToolbar sizeToFit];
UIBarButtonItem *flexBarButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil action:nil];
UIBarButtonItem *doneBarButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:#selector(yourTextViewDoneButtonPressed)];
keyboardToolbar.items = #[flexBarButton, doneBarButton];
self.yourTextView.inputAccessoryView = keyboardToolbar;
and then add yourTextViewDoneButtonPressed method
-(void)yourTextViewDoneButtonPressed
{
[self.yourTextView resignFirstResponder];
}
It can be done using storyboard:
Add UITextField to UIViewController view.
Add UIToolbar in the first level of UIViewController
Add UIBarButtonItem into the UIToolbar.
Connect UItoolbar to the code using IBOutlet.
Connect UIBarButtonItem to the code using IBAction (as didClick).
Make the UITextField will be delegating to UIViewController.
In the didClick function end editing (view.endEditing(true))
In the delegate function textFieldShouldBeginEditing should be: textField.inputAccessoryView = toolbar and returns true.
Swift 3:
func setDoneOnKeyboard() {
let keyboardToolbar = UIToolbar()
keyboardToolbar.sizeToFit()
let flexBarButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneBarButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(InsertStatusVC.dismissKeyboard))
keyboardToolbar.items = [flexBarButton, doneBarButton]
self.fullNameTextField.inputAccessoryView = keyboardToolbar
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
This Solution For Swift3+
Add This line To your Project As a extension
Your Problem is solved.
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()
}
}
Before extension
After extension
Solution for Swift 4 and Swift 5 using a custom class. You can use this class in your Storyboard and .xib files.
class UITextFieldWithDoneButton: UITextField {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.addDoneButtonOnKeyboard()
}
fileprivate 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 fileprivate func doneButtonAction() {
self.resignFirstResponder()
}
}
This Solution For Swift 4
override func viewDidLoad() {
super.viewDidLoad()
//init toolbar
let toolbar:UIToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 30))
//create left side empty space so that done button set on right side
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let doneBtn: UIBarButtonItem = UIBarButtonItem(title: “Done”, style: .done, target: self, action: Selector(“doneButtonAction”))
toolbar.setItems([flexSpace, doneBtn], animated: false)
toolbar.sizeToFit()
//setting toolbar as inputAccessoryView
self.textField1.inputAccessoryView = toolbar
self.textField2.inputAccessoryView = toolbar
}
func doneButtonAction() {
self.view.endEditing(true)
}
Add UIToolBar as custom view that will have UIBarButtonItem as Done button in it.
This is safer and cleaner way to add Done button to any Type of Keyboard. Create UIToolBar add Done Button to it and set inputAccessoryView of any UITextField or UITextView.
];
}
SWIFT 3
var ViewForDoneButtonOnKeyboard = UIToolbar()
ViewForDoneButtonOnKeyboard.sizeToFit()
var btnDoneOnKeyboard = UIBarButtonItem(title: "Done", style: .bordered, target: self, action: #selector(self.doneBtnFromKeyboardClicked))
ViewForDoneButtonOnKeyboard.items = [btnDoneOnKeyboard]
myTextField.inputAccessoryView = ViewForDoneButtonOnKeyboard
Function
#IBAction func doneBtnfromKeyboardClicked (sender: Any) {
print("Done Button Clicked.")
//Hide Keyboard by endEditing or Anything you want.
self.view.endEditing(true)
}
The answer from Ramis that allows the keyboard accessory view to be created using the Storyboard is a great strategy. It is 2017 after all! (Sorry, but I do not have enough points to upvote you.)
Let me add a little to the answer (to keep within the SO rules). I have a view with multiple textFields. After implementing each of Ramis' steps I attached the accessoryView to all of the textFields in this way:
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
_activeTextField = textField;
[_activeTextField setInputAccessoryView:_iboKeyboardTools];
}
So easy compared with implementing all this in code! Just build the accessory view in Storyboard- and attach it again and again!

How to change space between UIBarButtonItems in UINavigationBar?

This is how it looks now:
This is how it is represented in Debug view Hierarchy:
And here is how I set it up in code:
func setupUserAndCartButtons() {
var rightBarButtonItems = [UIBarButtonItem]()
let cartBarButtonItem = UIBarButtonItem(image: DBCart.sharedCart().icon, style: .Plain, target: self, action: Selector("cartButtonTapped:"))
rightBarButtonItems.append(cartBarButtonItem)
let userIcon = UIImage(named: "icon-user")
let userBarButtonItem = UIBarButtonItem(image: userIcon, style: .Plain, target: self, action: Selector("userButtonTapped:"))
rightBarButtonItems.append(userBarButtonItem)
navigationItem.rightBarButtonItems = rightBarButtonItems
}
Hot to move them closer to each other without using custom view?
use imageInsets property of UIBarButtonItem
In Objective-C
[addContact setImageInsets:UIEdgeInsetsMake(0, -10,0, 0)];
Swift 4.1
buttonName.imageInsets = UIEdgeInsetsMake(0, 30, 0, 0)
This will move button to right side to other button.
Hope this will help someone
Add buttons using custom View:
//MARK:Customize Navigation Bar
func addButtonsToNavigationBar(){
let cartButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
cartButton.frame = CGRectMake(0,0,20,20)
cartButton.addTarget(self, action: "cartButtonTapped:", forControlEvents: .TouchUpInside)
cartButton.setImage(UIImage(named: DBCart.sharedCart().icon), forState: .Normal)
let cartBarButtonItem = UIBarButtonItem(customView: cartButton)
let userButton = UIButton.buttonWithType(UIButtonType.Custom) as! UIButton
userButton.frame = CGRectMake(0,0,20,20)
userButton.addTarget(self, action: "userButtonTapped:", forControlEvents: .TouchUpInside)
userButton.setImage(UIImage(named: "icon-user"), forState: .Normal)
let userBarButtonItem = UIBarButtonItem(customView: userButton)
self.navigationItem.rightBarButtonItems=[cartBarButtonItem,userBarButtonItem]
}
UIBarButtonSystemItemFixedSpace is used to adjust spacings of navigation bar items.
Example code:
- (void)setRightBarButtonItems {
UIBarButtonItem *addTaskButton =
[[UIBarButtonItem alloc] bk_initWithBarButtonSystemItem:UIBarButtonSystemItemAdd
handler:handler];
UIBarButtonItem *negativeSeperator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
if ([UIDevice isIOS7Plus]) {
negativeSeperator.width = -12;
} else {
negativeSeperator.width = -8;
}
UIBarButtonItem *separator = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
separator.width = 50;
[self.navigationItem setRightBarButtonItems:#[addTaskButton, separator, [self filterButton]]];
}

Swift IOS - Using UIPickerView AND Keyboard

In my app when user clicks on UITextField he should be able to pick up a value from UIPickerView OR enter his own value using keyboard.
What's the best way of doing it in terms of user experience and ease of implementation?
UIPickerView with toolbar is already implemented.
I'd appreciate both advice on best way of doing it and example code of switching keyboard <-> pickerview.
I've tried adding a button "Show keyboard" on pickerview's toolbar and adding the following code:
func showKeyboard() {
selectedTextField.inputView = nil
}
But clicking this button doesn't do anything. Also I'm not sure it's a good way in terms of UX.
Here's the solution:
var useKeyboard:Bool = true
func showKeyboard() {
if useKeyboard {
useKeyboard = false
selectedTextField.inputView = nil
selectedTextField.reloadInputViews()
selectedTextField.keyboardAppearance = UIKeyboardAppearance.Default
selectedTextField.keyboardType = UIKeyboardType.Default
} else {
useKeyboard = true
selectedTextField.inputView = nil
selectedTextField.reloadInputViews()
createPicker(selectedTextField)
selectedTextField.resignFirstResponder()
selectedTextField.becomeFirstResponder()
}
}
// That's my custom picker - adjust whatever you need
func createPicker(sender: UITextField){
selectedTextField = sender
// Create picker view
var newPickerView: UIPickerView
newPickerView = UIPickerView(frame: CGRectMake(0, 200, view.frame.width, 300))
newPickerView.backgroundColor = .whiteColor()
// Only for UIPickerView
newPickerView.showsSelectionIndicator = true
newPickerView.delegate = self
newPickerView.dataSource = self
// Create toolbar
var toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.Default
toolBar.translucent = true
toolBar.tintColor = UIColor(red: 76/255, green: 217/255, blue: 100/255, alpha: 1)
toolBar.sizeToFit()
// Create buttons
var doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Plain, target: self, action: "donePicker")
var spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
var cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Plain, target: self, action: "cancelPicker")
var customButton = UIBarButtonItem(title: "Keyboard", style: UIBarButtonItemStyle.Plain, target: self, action: "showKeyboard")
// Assign buttons to toolbar
toolBar.setItems([cancelButton, spaceButton, customButton, doneButton], animated: false)
toolBar.userInteractionEnabled = true
// Add pickerview and toolbar to textfield
sender.inputView = newPickerView
sender.inputAccessoryView = toolBar
}
func donePicker() {
useKeyboard = true
selectedTextField.resignFirstResponder()
}
func cancelPicker() {
useKeyboard = true
selectedTextField.resignFirstResponder()
}

Add buttons to UIPickerView - Swift 1.2

I would like to add two UIButtons in the UIPickerView (on top of it). Please take a look at the Cancel and Done buttons in this image:
How can I do it?
I have solved this, answer in Swift:
var pickerView = UIPickerView(frame: CGRectMake(0, 200, view.frame.width, 300))
pickerView.backgroundColor = .whiteColor()
pickerView.showsSelectionIndicator = true
var toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.Default
toolBar.translucent = true
toolBar.tintColor = UIColor(red: 76/255, green: 217/255, blue: 100/255, alpha: 1)
toolBar.sizeToFit()
let doneButton = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Bordered, target: self, action: "donePicker")
let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
let cancelButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Bordered, target: self, action: "canclePicker")
toolBar.setItems([cancelButton, spaceButton, doneButton], animated: false)
toolBar.userInteractionEnabled = true
textField.inputView = pickerView
textField.inputAccessoryView = toolBar
See Mine. I have Collection View and UIPicker to select photo Folders.
//MARK:- SHOW PHOTO FOLDER BUTTON METHOD
#IBAction func photoFolderListButtonClicked(sender: UIButton) {
self.navigationItem.setHidesBackButton(true, animated: true)
//Making PickerView of Competitors
let DEVICE_SCREEN_WIDTH = UIScreen.mainScreen().bounds.size.width
photoFolderListPicker.frame = CGRectMake(0.0, 44.0, DEVICE_SCREEN_WIDTH, 260)
photoFolderListPicker.dataSource = self
photoFolderListPicker.delegate = self
photoFolderListPicker.showsSelectionIndicator = true;
photoFolderListPicker.backgroundColor = UIColor.whiteColor()
let pickerDateToolbar = UIToolbar(frame: CGRectMake(0, 0, DEVICE_SCREEN_WIDTH, 44))
pickerDateToolbar.barStyle = UIBarStyle.Black
pickerDateToolbar.barTintColor = UIColor.blackColor()
pickerDateToolbar.translucent = true
//Cancel button on photoFolderListPicker
let barItems = NSMutableArray()
let labelCancel = UILabel()
labelCancel.text = " Cancel"
let titleCancel = UIBarButtonItem(title: labelCancel.text, style: UIBarButtonItemStyle.Plain, target: self, action: Selector("cancelPickerSelectionButtonClicked:"))
titleCancel.tintColor = UIColor.whiteColor()
barItems.addObject(titleCancel)
var flexSpace: UIBarButtonItem
flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: self, action: nil)
barItems.addObject(flexSpace)
//Done Button on photoFolderListPicker
let doneBtn = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: Selector("photoFolderSelectionDone:"))
barItems.addObject(doneBtn)
doneBtn.tintColor = UIColor.whiteColor()
pickerDateToolbar.setItems(barItems as [AnyObject] as? [UIBarButtonItem], animated: true)
actionView.addSubview(pickerDateToolbar)
actionView.addSubview(photoFolderListPicker)
if (window != nil) {
window!.addSubview(actionView)
}
else {
self.view.addSubview(actionView)
}
UIView.animateWithDuration(0.2, animations: {
self.actionView.frame = CGRectMake(0, UIScreen.mainScreen().bounds.size.height - 250.0, UIScreen.mainScreen().bounds.size.width, 250)
})
}
//MARK:- PICKERVIEW DELEGATE METHODS
func pickerView(_pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return model.documentFolders.count
}
func numberOfComponentsInPickerView(_pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! {
return model.documentFolders[row].value
}
//MARK:- PICKERVIEW BUTTON METHODS
func cancelPickerSelectionButtonClicked(sender: UIBarButtonItem) {
self.navigationItem.setHidesBackButton(false, animated: true)
UIView.animateWithDuration(0.2, animations: {
self.actionView.frame = CGRectMake(0, UIScreen.mainScreen().bounds.size.height, UIScreen.mainScreen().bounds.size.width, 210.0)
}, completion: { _ in
for obj: AnyObject in self.actionView.subviews {
if let view = obj as? UIView
{
view.removeFromSuperview()
}
}
})
photoFolderListButton.setTitle(" "+"Select Folder", forState: UIControlState.Normal)
}
func photoFolderSelectionDone(sender: UIBarButtonItem) {
uploadedPhotoFolderName?.isEmpty
loadedFromPageSection = "fromPhotoFolderSelectionDone"
self.disableScoutDetailUserInterfaceElementsDutingApiCall()
//setting selectedPhotoFolderItem and selectedPhotoFolderItemId
let myRow = photoFolderListPicker.selectedRowInComponent(0)
selectedPhotoFolderItem = model.documentFolders[myRow].value!
selectedPhotoFolderItemId = Int(model.documentFolders[myRow].key!)
UIView.animateWithDuration(0.2, animations: {
self.actionView.frame = CGRectMake(0, UIScreen.mainScreen().bounds.size.height, UIScreen.mainScreen().bounds.size.width, 260.0)
}, completion: { _ in
for obj: AnyObject in self.actionView.subviews {
if let view = obj as? UIView
{
view.removeFromSuperview()
}
}
})
photoFolderListButton.setTitle(" "+(selectedPhotoFolderItem as? String)!, forState: UIControlState.Normal)
self.view.makeToastActivityWithMessage(message: "Fetching")
//Delegate is added to class after popViewControllerAnimated(true) called
model.delegate = self
//API CALL - Fetching Photos
AppController().fetchPropertyPhotosGallery(hbId, propertyId: scoutPropertyId, fileTypeId: selectedPhotoFolderItemId)
}
Here is how I do it in ObjC to add a picker popup with buttons to a text field. Should be simple enough to translate into swift. Basically you create the picker and assign it to the text inputView. Then you create a toolbar which you assign to the text inputAccessoryView which sits on top of the inputView when it pops up.
self.manufacturerPicker = [[UIPickerView alloc] initWithFrame:CGRectZero];
self.manufacturerPicker.delegate = self;
self.manufacturerPicker.dataSource = self;
[self.manufacturerPicker setShowsSelectionIndicator:YES];
self.filterByManufacturerTextField.inputView = self.manufacturerPicker;
UIToolbar *manufacturerPickerToolbar=[[UIToolbar alloc] init];
manufacturerPickerToolbar.barStyle = UIBarStyleBlack;
manufacturerPickerToolbar.translucent = YES;
manufacturerPickerToolbar.tintColor = nil;
[manufacturerPickerToolbar sizeToFit];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered target:self
action:#selector(manufacturerPickerDoneClicked:)];
UIBarButtonItem *spacerButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel"
style:UIBarButtonItemStyleBordered target:self
action:#selector(manufacturerPickerCancelClicked:)];
[manufacturerPickerToolbar setItems:#[cancelButton,spacerButton,doneButton]];
self.filterByManufacturerTextField.inputAccessoryView = manufacturerPickerToolbar;
Updated for when you have no UITextField as the start point:
If you want to launch a picker from a cell as if it was a text field picker, I believe you have to make your UITableViewCell implement the process of becoming the first responder.
To do this I think the process is to implement the UIResponder protocol in your cell.
1) override canBecomeFirstResponder and return YES.
2) override inputView property getter. In this code return your UIPickerView.
§3) override inputAccessoryView property getter. In this code return your UIToolbar.
Now in your cell when you select the cell, make the cell become the first responder by calling [self becomeFirstResponder];.
This should then bring the picker and toolbar up properly I think. There may be more to this.
When cancel or done, drop it using [self resignFirstResponder];
Not done this before, but I think this is the general process.
Option 2 (Cheat):
Sometimes cheating is easier. Add a hidden UITextField at the back of your cell or add one which is 0 width. Set its inputView and inputAccessoryView as per the original suggestion.
Then when you select the cell simply make the UITextField the first responder using [self.<your text field property> becomeFirstResponder];
This should give you the same result via the back door.

How can I add a toolbar above the keyboard?

I have created a UIToolBar programmatically and added a UITextField on it. Now, I need that toolbar to be above the keyboard when I click in another text field.
UIToolbar *toolBar=[[UIToolbar alloc]initWithFrame:CGRectMake(0,400, 320, 60)];
[self.view addSubview:toolBar];
UITextField *txtView=[[UITextField alloc]initWithFrame:CGRectMake(0, 400, 260, 30)];
txtView.backgroundColor =[UIColor grayColor];
txtView.placeholder=#"Address";
UIBarButtonItem *txtfieldItem=[[UIBarButtonItem alloc]initWithCustomView:txtView];
toolBar.items =[NSArray arrayWithObject:txtfieldItem];
UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 50)];
numberToolbar.barStyle = UIBarStyleBlackTranslucent;
numberToolbar.items = [NSArray arrayWithObjects:
[[UIBarButtonItem alloc]initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:self action:#selector(cancelNumberPad)],
[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
[[UIBarButtonItem alloc]initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(doneWithNumberPad)],
nil];
[numberToolbar sizeToFit];
phonenumberTextField.inputAccessoryView = numberToolbar;
To Dismiss Keyboard:
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder) to:nil from:nil forEvent:nil];
Swift 3:
let numberToolbar = UIToolbar(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, 50))
numberToolbar.barStyle = UIBarStyle.Default
numberToolbar.items = [
UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Plain, target: self, action: "cancelNumberPad"),
UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil),
UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Plain, target: self, action: "doneWithNumberPad")]
numberToolbar.sizeToFit()
phonenumberTextField.inputAccessoryView = numberToolbar
Swift 4.2:
let numberToolbar = UIToolbar(frame:CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
numberToolbar.barStyle = .default
numberToolbar.items = [
UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(cancelNumberPad)),
UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneWithNumberPad))]
numberToolbar.sizeToFit()
phonenumberTextField.inputAccessoryView = numberToolbar
...
#objc func cancelNumberPad() {
//Cancel with number pad
}
#objc func doneWithNumberPad() {
//Done with number pad
}
You do not need to do this in code anymore.
Just simply drag UIView to the top bar of current scene and customize it as you want.
In code simply put IBOutlet for both: toolbarView and textView and make connections.
#IBOutlet private var toolbarView: UIView!
#IBOutlet private var textView: UITextView!
In viewDidLoad setup your toolbarView as accessoryView of your UItextView.
override func viewDidLoad() {
super.viewDidLoad()
textView.inputAccessoryView = toolbarView
}
The result is following:
For swift (1.2):
let numberToolbar = UIToolbar(frame: CGRectMake(0, 0, self.view.frame.size.width, 50))
numberToolbar.barStyle = UIBarStyle.Default
numberToolbar.items = [
UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Plain, target: self, action: "keyboardCancelButtonTapped:"),
UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil),
UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Plain, target: self, action: "keyboardDoneButtonTapped:")]
numberToolbar.sizeToFit()
yourTextView.inputAccessoryView = numberToolbar
You Can Use this code it work for me.
-(void)viewdidload
{
UIToolbar* keyboardDoneButtonView = [[UIToolbar alloc] init];
[keyboardDoneButtonView sizeToFit];
UIBarButtonItem* doneButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered target:self
action:#selector(doneClicked:)];
[keyboardDoneButtonView setItems:[NSArray arrayWithObjects:doneButton, nil]];
textField.inputAccessoryView = keyboardDoneButtonView;
}
-(void)doneClicked:(id)sender
{
NSLog(#"Done Clicked.");
[self.view endEditing:YES];
}
You can use the UITextFields inputAccessoryView property
txtField.inputAccessoryView = toolBar;
Swift 3
let toolBar = UIToolbar(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 50))
toolBar.barStyle = UIBarStyle.default
toolBar.items = [
UIBarButtonItem(title: "Button1", style: UIBarButtonItemStyle.plain, target: self, action: #selector(test2)),
UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil),
UIBarButtonItem(title: "Button2", style: UIBarButtonItemStyle.plain, target: self, action: #selector(test1))]
toolBar.sizeToFit()
myTextField.inputAccessoryView = toolBar
Swift 5.0 and above
let toolBar = UIToolbar(frame: CGRect(x: 0.0,
y: 0.0,
width: UIScreen.main.bounds.size.width,
height: 44.0))//1
let flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)//2
let DoneButton = UIBarButtonItem(title: "Done", style: .plain, target: target, action: #selector(tapDone))//3
toolBar.setItems([flexibleSpace, DoneButton], animated: false)
textField.inputAccessoryView = toolBar
// Done Action
#objc func tapDone() {
self.view.endEditing(true)
}
textField.inputAccessoryView=[weakSelf addToolBar];
[textField setKeyboardType:UIKeyboardTypeNumberPad];
and add a method
-(UIToolbar *)addToolBar
{
UIBarButtonItem *done=[[UIBarButtonItem alloc]initWithTitle:#"DONE" style:UIBarButtonItemStyleDone target:self action:#selector(done:)];
UIToolbar *toolBar=[[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 30)];
NSArray* toolBarItems=[[NSArray alloc]initWithObjects:done, nil];
[toolBar setItems:toolBarItems];
return toolBar;
}
In Swift 3 and 4
let toolBar = UIToolbar()
toolBar.barStyle = UIBarStyle.default
toolBar.isTranslucent = true
toolBar.isUserInteractionEnabled = true
toolBar.sizeToFit()
toolBar.items = [
UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.plain, target: self, action: #selector(self.sendCodeBtnAction(sender:)))]
tfPhone.inputAccessoryView = toolBar

Resources