Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to input text using the buttons of an in-app custom keyboard

I've made an in-app custom keyboard that replaces the system keyboard and pops up when I tap inside a UITextField.

enter image description here

Here is my code:

class ViewController: UIViewController {
    
    var myCustomKeyboard: UIView!
    @IBOutlet weak var textField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let keyboardNib = UINib(nibName: "Keyboard", bundle: nil)
        myCustomKeyboard = keyboardNib.instantiateWithOwner(self, options: nil)[0] as! UIView
        
        textField.inputView = myCustomKeyboard
    }

}

The keyboard layout is loaded from an xib file.

Question

How do I get the button text into the text field?

Notes:

  • There are many tutorials about making a custom system keyboard (which needs to be installed), but I only want an in-app keyboard. The tutorials use a special view controller just for the keyboard, but here it seems that I am just setting the keyboard view.
  • I have read the Custom Views for Data Input documentation.
  • This is the closest Stack Overflow question I could find, but it doesn't go as far as describing how to get the text from the buttons.

Update

  • This tutorial seems to indicate that there is a view controller for the custom input view. However, I am getting lost in the Objective-C code. What would be the process in Swift?
  • This answer mentions the UIKeyInput protocol that UITextField conforms to, but how do I use it?
  • If there is any built in way too make a custom in-app keyboard, I would really prefer that to making a normal custom view.
like image 902
Suragch Avatar asked Nov 03 '15 11:11

Suragch


2 Answers

I imagine something like this:

A new function to handle button event

func updateTextfield(sender: UIButton) {
    textField.text = (textField.text ?? "") + (sender.titleForState(.Normal) ?? "")
}

And after init your custom keyboard, register the buttons:

myCustomKeyboard.subviews
    .filter { $0 as? UIButton != nil } // Keep the buttons only
    .forEach { ($0 as! UIButton).addTarget(self, action: "updateTextfield", forControlEvents: .TouchUpInside)}
like image 57
awph Avatar answered Nov 06 '22 09:11

awph


Setup

  • Make an xib file that includes all your keys
  • Use Autolayout so that the keys will resize to the correct proportions no matter how big the keyboard is set to later.
  • Create a swift file with the same name as the xib file and set it as the file owner in the xib file setting.

    enter image description here

    enter image description here enter image description here

  • Hook up all the key buttons to an IBAction method in the swift file. (See the code below.)

Code

I'm using the delegate pattern to communicate between the custom keyboard view and the main view controller. This allows them to be decoupled. Multiple different custom keyboards could be swapped in and out without needing to change the detailed implementation code in the main view controller.

Keyboard.swift file

import UIKit

protocol KeyboardDelegate {
    func keyWasTapped(character: String)
}

class Keyboard: UIView {

    var delegate: KeyboardDelegate?

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initializeSubviews()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        initializeSubviews()
    }

    func initializeSubviews() {
        let xibFileName = "Keyboard" // xib extention not needed
        let view = NSBundle.mainBundle().loadNibNamed(xibFileName, owner: self, options: nil)[0] as! UIView
        self.addSubview(view)
        view.frame = self.bounds
    }

    @IBAction func keyTapped(sender: UIButton) {
        self.delegate?.keyWasTapped(sender.titleLabel!.text!)
    }

}

Main view controller

Note that the ViewController conforms to the KeyboardDelegate protocol that we created. Also, when creating an instance of the keyboard view, the height needs to be set but the width doesn't. Apparently setting the inputView of the text field updates the keyboard view width to the screen width, which is convenient.

class ViewController: UIViewController, KeyboardDelegate {

    @IBOutlet weak var textField: UITextField!

    override func viewDidLoad() {
        super.viewDidLoad()

        // get an instance of the Keyboard (only the height is important)
        let keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 300))

        // use the delegate to communicate
        keyboardView.delegate = self

        // replace the system keyboard with the custom keyboard
        textField.inputView = keyboardView
    }

    // required method for keyboard delegate protocol
    func keyWasTapped(character: String) {
        textField.insertText(character)
    }

}

Sources

  • The suggestions in @ryancrunchi's comment were helpful.
  • This answer from Creating a reusable UIView with xib (and loading from storyboard)

Related

  • A Swift example of Custom Views for Data Input (custom in-app keyboard)
like image 27
Suragch Avatar answered Nov 06 '22 09:11

Suragch