1

My current assignment is an iOS Keyboard Extension. Now, to pass App Store Review, the containing app has to provide some "real" content. I thought about letting the user test the keyboard before enabling it in the Settings. So my storyboard looks like this (reduced to show relevant stuff):

└ ViewController
  └ View
    ├ TextField
    └ Keyboard Container
      └ KeyboardViewController

This works all right, the keyboard shows in the container, but - as the textDocumentProxy object in the keyboard's view controller isn't attached to anything - the user can't see what s/he's typing.

Now I'm looking for a way to "attach" the keyboard to the text field, while keeping the system keyboard out of the way so the user can type on the custom one.

I already managed to get the system keyboard away by attaching the following function to the textfield's editing did begin action.

@IBAction func editingBegan(sender: UITextField) {
    sender.endEditing(true)
}
s3lph
  • 4,575
  • 4
  • 21
  • 38

1 Answers1

2

I managed to find the following workaround:

I created a class which implemented the UITextDocumentProxy protocol, which writes to the text field, and set this as an additional proxy in the keyboard view controller:

class ProxyWrapper: NSObject, UITextDocumentProxy {

    private let textField: UITextField

    init(textField: UITextField) {
        self.textField = textField
    }

    var documentContextBeforeInput: String? {
        get {
            return textField.text
        }
    }

    var documentContextAfterInput: String? {
        get {
            return ""
        }
    }

    func adjustTextPositionByCharacterOffset(offset: Int) {}

    func insertText(text: String) {
        let ntext = text.stringByReplacingOccurrencesOfString("\n", withString: "")
        textField.text = (textField.text ?? "") + ntext
    }

    func deleteBackward() {
        if let text = textField.text {
            textField.text = text.substringToIndex(text.endIndex.advancedBy(-1))
        }
    }

    func hasText() -> Bool {
        return textField.hasText()
    }

}

As you can see, I only implemented a very minimalist class (text input/deletion only at the end), as I disabled user interactivity altogether for the text field so no "real" keyboard would ever pop up. Also, I don't allow the insertion of newlines.

It may seem a bit hackish and there may be solutions way better (feel free to tell me), but this works and thus I used it.

s3lph
  • 4,575
  • 4
  • 21
  • 38