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.
Related
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
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.
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!
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()
}
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 ....