How to add button above the keyboard like this one in Stack Exchange app? And when you long press the text in UITextView How to add "Select" and "Select All"?
The first question, you can set textField's inputAccessoryView to your custom view, this can customize the keyboard's header.
The result:
You can do it like below;
first, you should instance the view you want to add above the keyboard.
class ViewController : UIViewController {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.inputAccessoryView = Bundle.main.loadNibNamed("CustomAccessoryView", owner: self, options: nil)?.first as! UIView?
In your CustomAccessoryView, you can set the action of the button:
import UIKit
class CustomAccessoryView: UIView {
#IBAction func clickLoveButton(_ sender: UIButton) {
print("Love button clicked")
}
}
I would recommend to create a toolbar for your UITextField's accessoryView property.
The idea is to add this toolbar once, before the textfield would show for the first time. Therefore, we assign the delegate to self, and override the textFieldShouldBeginEditing delegate call with our implementation to add the accessoryView.
Here is a simple example, how can u achieve it:
import UIKit
class ViewController: UIViewController {
// your `UITextfield` instance
// Don't forget to attach it from the IB or create it programmaticly
#IBOutlet weak var textField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Assign the delegate to self
textField.delegate = self
}
}
// MARK: Create extension to conform to UITextfieldDelegate
extension ViewController: UITextFieldDelegate {
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
setupTextFieldsAccessoryView()
return true
}
func setupTextFieldsAccessoryView() {
guard textField.inputAccessoryView == nil else {
print("textfields accessory view already set up")
return
}
// Create toolBar
let toolBar: UIToolbar = UIToolbar(frame:CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 44))
toolBar.barStyle = UIBarStyle.black
toolBar.isTranslucent = false
// Add buttons as `UIBarButtonItem` to toolbar
// First add some space to the left hand side, so your button is not on the edge of the screen
let flexsibleSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil) // flexible space to add left end side
// Create your first visible button
let doneButton: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: self, action: #selector(didPressDoneButton))
// Note, that we declared the `didPressDoneButton` to be called, when Done button has been pressed
toolBar.items = [flexsibleSpace, doneButton]
// Assing toolbar as inputAccessoryView
textField.inputAccessoryView = toolBar
}
func didPressDoneButton(button: UIButton) {
// Button has been pressed
// Process the containment of the textfield or whatever
// Hide keyboard
textField.resignFirstResponder()
}
}
This should be your output:
You'll have to use the inputAccessoryView of your textfield.
you can put the code snippet below in your viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 60))
button.backgroundColor = UIColor.blue
button.setTitle("NEXT", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.addTarget(self, action: #selector(self. yourButton), for: .touchUpInside)
numtextField.inputAccessoryView = button
}
#objc func nextButton()
{
print("do something")
}
Just copy and paste simple code for you accessory button embedded with keypad
func addKeyboardToolbar() {
let ViewForDoneButtonOnKeyboard = UIToolbar()
ViewForDoneButtonOnKeyboard.sizeToFit()
let button = UIButton.init(type: .custom)
button.setImage(UIImage.init(named: "login-logo"), for: UIControlState.normal)
button.addTarget(self, action:#selector(doneBtnfromKeyboardClicked), for:.touchUpInside)
button.frame = CGRect.init(x: 0, y: 0, width:UIScreen.main.bounds.width, height: 30) //CGRectMake(0, 0, 30, 30)
let barButton = UIBarButtonItem.init(customView: button)
ViewForDoneButtonOnKeyboard.items = [barButton]
postTextView.inputAccessoryView = ViewForDoneButtonOnKeyboard
}
func doneBtnfromKeyboardClicked (){
self.contentView.endEditing(true)
}
to add a toolbar with a done button which dismisses the keyboard above a UITextField you can write a UITextField extension with the following function:
public func addAccessoryView() {
let doneButton = UIBarButtonItem.init(barButtonSystemItem: UIBarButtonSystemItem.Done, target: self, action: "resignFirstResponder")
let flexSpace: UIBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: self, action: nil)
let toolbar = UIToolbar()
toolbar.barStyle = UIBarStyle.Default
toolbar.translucent = true
toolbar.tintColor = Color.blue
toolbar.sizeToFit()
toolbar.setItems([flexSpace, doneButton], animated: false)
toolbar.userInteractionEnabled = true
self.inputAccessoryView = toolbar
}
you can then call the function in your textfield like this:
textfield.addAccessoryView()
Related
Below my question is the code i'm using in xCode 10 to place a "Done" button on the pop up keyboard.
I have a second ViewController but don't know how to use this code on this second one. The errors displayed in my second ViewController are:
Invalid redeclaration of 'doneAccessory'
Invalid redeclaration of 'addDoneButtonOnKeyboard()'
Invalid redeclaration of 'doneButtonAction()'
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()
}
}
Please add this UITexfield extension to your helper class. Its good practice having all your extensions in the helper class.
You need not set anything about your second view controller. You need to open your storyboard and select the text field where you want the done button. Find the image to set the done button then you will not face any issue.
I’m trying to change the default look of Navigation Controller back button across my app.
I would like to use and image(icon) and remove the “Back” text.
This code stretched the image across the button and does not remove the button title.
let backImg: UIImage = UIImage(named: "icon_back")!
UIBarButtonItem.appearance().setBackButtonBackgroundImage(backImg, for: .normal, barMetrics: .default)
An recommendation how to do is inside AppDelegate (didFinishLaunchingWithOptions)?
The easy way of doing is just create one BaseViewController for your project which is derived from UIViewController. You can have on common method in BaseViewController to create your custom leftBarButton in every viewController. The remaining viewController in your project should be derived from this BaseViewController,
class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
createLeftBarButton(image: #Pass image here#, width: #Pass width of your image view#) // Create custom back bar button.
}
/**Create cutom back bar button*/
func createLeftBarButton(image: UIImage?, width: CGFloat) {
let backButton: UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: width, height: 50))
backButton.imageView?.contentMode = .scaleAspectFill
backButton.imageView?.bounds = CGRect(x: 0, y: 0, width: width, height: width)
backButton.setImage(image, for: .normal)
backButton.setImage(image, for: .highlighted)
backButton.addTarget(self, action: #selector(leftBarButtonItemPressed(_:)), for: .touchUpInside)
let leftItem: UIBarButtonItem = UIBarButtonItem(customView: backButton)
navigationItem.leftBarButtonItem = leftItem
}
/**Custom back bar button pressed. So handle here*/
func leftBarButtonItemPressed(_ sender: UIButton) {
view.endEditing(true) // End editing if any.
if isViewControllerPresented() { // Check view controller is presented or pushed
dismiss(animated: true, completion: nil) // Dismiss ViewController if presented
} else {
_ = navigationController?.popViewController(animated: true) // Pop ViewController if pushed
}
}
/**To check whether view controller is presented or pushed.*/
func isViewControllerPresented() -> Bool {
if self.presentingViewController?.presentedViewController == self {
return true
}
if (self.navigationController != nil && self.navigationController?.presentingViewController?.presentedViewController == self.navigationController) && self.navigationController?.viewControllers.count == 1 {
return true
}
if self.tabBarController?.presentingViewController is UITabBarController {
return true
}
return false
}
}
// Sub class your remaining viewControllers like this.
class FirstViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad() // When calling this super method, the custom back bar button will be created for you
}
}
Thanks.
You can doing this by setting the navigationItem's BackButtonBackgroundImage;
also you can set the appearance for global effect:
let item = UIBarButtonItem.appearance(whenContainedInInstancesOf: [UINavigationBar.self])
item.setBackButtonBackgroundVerticalPositionAdjustment(-10, for: .default) item.setBackButtonBackgroundImage(youImage, for: .normal, barMetrics: .default)
for removing the back title, you can do like this:
#implementation UINavigationItem (BackItem)
-(UIBarButtonItem *)backBarButtonItem {
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:#" " style:UIBarButtonItemStylePlain target:nil action:nil];
item.tintColor = [UIColor darkGrayColor];
return item;
}
#end
I'm using two textField which is of numPad keyboard type. I have added Next button for the first textField and Done button for the second textField in the numPad keyboard. Using the following code.
import UIKit
class SecurityPinSettingsVC: UIViewController, UITextFieldDelegate
{
#IBOutlet weak var textField1: UITextField!
#IBOutlet weak var textField2: UITextField!
override func viewDidLoad()
{
super.viewDidLoad()
self.textField1.delegate = self
self.textField2.delegate = self
self.textField1.textAlignment = NSTextAlignment.center
self.textField2.textAlignment = NSTextAlignment.center
addNextButtonOnKeyboard()
addDoneButtonOnKeyboard()
}
func addNextButtonOnKeyboard()
{
let nextToolbar: UIToolbar = UIToolbar(frame: CGRect(x: 0,y: 0, width: 320, height: 50))
nextToolbar.barStyle = UIBarStyle.default
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let next: UIBarButtonItem = UIBarButtonItem(title: "Next", style: UIBarButtonItemStyle.done, target: self, action: #selector(ViewController.doneButtonAction))
var items = [UIBarButtonItem]()
items.append(flexSpace)
items.append(next)
nextToolbar.items = items
nextToolbar.sizeToFit()
self.textField1.inputAccessoryView = nextToolbar
}
func addDoneButtonOnKeyboard()
{
let doneToolbar: UIToolbar = UIToolbar(frame: CGRect(x: 0, y: 0, width: 320, height: 50))
doneToolbar.barStyle = UIBarStyle.default
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.flexibleSpace, target: nil, action: nil)
let ddone: UIBarButtonItem = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(ViewController.doneButtonAction))
var items = [UIBarButtonItem]()
items.append(flexSpace)
items.append(ddone)
doneToolbar.items = items
doneToolbar.sizeToFit()
self.textField2.inputAccessoryView = doneToolbar
}
func doneButtonAction()
{
//self.textField2.becomeFirstResponder()
//self.textField2.resignFirstResponder()
}
}
Both buttons are successfully added. The problem is, I could not create separate action methods for Next button and Done button. It accepts only doneButtonAction method for both buttons, which I have created and used in previous viewControllers. So, How can I get the textField id in the doneButtonAction method, in-order to know which button is clicked. So that, by clicking on Next button I want to make textField2 to become first responder, and by clicking Done button I want textField2 to resign first responder.
Like in ordinary textField, textFieldShouldReturn method will do this job easily, where the textField object will be passed to that function as an argument.
Here, how can we pass the textField object to the doneButtonAction method.
I'm using Xcode 8.2, Swift 3.0
Thanks in Advance.
you can get text field which are become responder
if textField1.isFirstResponder {
// textfield 1 is becomeResponder
}
I'm trying to add a "Done" button to a text field.
The black UIToolbar is displaying, but the "Done" button is not.
In the attributes inspector, 'Return key' is set to 'Done' and 'Auto-enable Return Key' is enabled.
The UITextField is connected to the delegate
This is inside a UITableViewCell:
import UIKit
class itemTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet var itemName: UILabel!
#IBOutlet var itemInput: UITextField!
var textFieldIsBeingEdited: Bool = false
override func awakeFromNib() {
super.awakeFromNib()
itemInput.delegate = self
self.addDoneButtonToKeyboard()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func addDoneButtonToKeyboard(){
let doneToolbar: UIToolbar = UIToolbar(frame: CGRectMake(0, 0, 320, 50))
doneToolbar.barStyle = UIBarStyle.BlackTranslucent
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
let done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: itemInput, action: Selector("doneButtonAction"))
let items = NSMutableArray()
items.addObject(flexSpace)
items.addObject(done)
doneToolbar.sizeToFit()
itemInput.inputAccessoryView = doneToolbar
}
func doneButtonAction()
{
self.itemInput.resignFirstResponder()
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
textField.resignFirstResponder()
return true
}
}
you forget to add the items to your let doneToolbar: UIToolbar
doneToolbar.items = items as [AnyObject]
brief answer
items.addObject(flexSpace)
items.addObject(done)
doneToolbar.items = items as [AnyObject]
doneToolbar.sizeToFit()
itemInput.inputAccessoryView = doneToolbar
I followed a tutorial online to add a custom toolbar and a done button to a keyboard. Xcode does not give me any errors, but when I run my app, there is no toolbar or done button an my keyboard. What did I do wrong in my code? Thanks!
Here is my code-
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var textField: UITextField!
override func viewDidLoad()
{
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textFieldShouldBeginEditing(textField: UITextField) -> Bool {
let keyboardDoneButtonShow = UIToolbar(frame: CGRectMake(200,200, self.view.frame.size.width,30))
keyboardDoneButtonShow.barStyle = UIBarStyle .BlackTranslucent
let button: UIButton = UIButton()
button.frame = CGRectMake(0, 0, 65, 20)
button.setTitle("Done", forState: UIControlState .Normal)
button.addTarget(self, action: Selector("textFieldShouldReturn:"), forControlEvents: UIControlEvents .TouchUpInside)
button.backgroundColor = UIColor .clearColor()
let doneButton: UIBarButtonItem = UIBarButtonItem()
doneButton.customView = button
let negativeSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil)
negativeSpace.width = -10.0
let flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
let toolbarButton = [flexSpace,doneButton,negativeSpace]
keyboardDoneButtonShow.setItems(toolbarButton, animated: false)
textField.inputAccessoryView = keyboardDoneButtonShow
return true
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
}
Here is my result-
I think you have not set your TextField's delegate to your View Controller. In viewDidLoad add the following:
self.textField.delegate = self