Text Field- Show what is inside the text field right above the keyboard

In part of my app, there is a text field near the very bottom of the screen. The problem is, once the user starts editing it, the keyboard is in the way and they can't see what is inside the text field.


I've seen apps before that have a white text field style box right on top of the keyboard that shows everything that is inside the text field. Is there a way to tell the keyboard to have this text preview, or would I have to manually program and move a custom text field above the keyboard to achieve this?


Thanks!

Accepted Reply

you can also move the whole view up above keyboard and moves the view back when editing is done.

Replies

you can also move the whole view up above keyboard and moves the view back when editing is done.

I’ve struggled with this for, oh, about a decade )-: Eventually I moved the core code out into a separate helper type (pasted in below). If my content is in a scroll view, I set it up and respond as follows:

var avoider: KeyboardAvoider? = nil

override func viewDidLoad() {
    …

    let avoider = KeyboardAvoider(view: self.mainText)
    avoider.delegate = self
    self.avoider = avoider

    …
}

func inset(by inset: CGFloat, keyboardAvoider: KeyboardAvoider) {
    let insets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: inset, right: 0.0)
    self.mainText.contentInset = insets 
    self.mainText.scrollIndicatorInsets = insets
    // UITextView seems to take care of the 'scoll active text to be visible' problem.
}

If my content is just a bunch of separate views I put an invisible wrapper view around them and then set up a constraint in order to inset that wrapper view. My delegate callback adjusts the constant on that constraint, like this:

func inset(by inset: CGFloat, keyboardAvoider: KeyboardAvoider) {
    self.bottomConstraint.constant = inset 
}

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
import UIKit

class KeyboardAvoider : NSObject {

    typealias Delegate = KeyboardAvoiderDelegate

    private override init() {
        fatalError()
    }

    required init(view: UIView) {
        self.view = view
        super.init()
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidShow(note:)), name: .UIKeyboardDidShow, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(note:)), name: .UIKeyboardWillHide, object: nil)
    }

    let view: UIView

    weak var delegate: Delegate? = nil

    deinit {
        NotificationCenter.default.removeObserver(self)
    }

    private static let logTransitions = false

    @objc func keyboardDidShow(note: Notification) {
        let new = (note.userInfo![UIKeyboardFrameEndUserInfoKey]! as! NSValue).cgRectValue
        let newInViewCoordinates = self.view.superview!.convert(new, from: UIScreen.main.coordinateSpace)
        let keyboardTop = newInViewCoordinates.minY
        let viewBottom = self.view.frame.maxY

        let inset: CGFloat
        if keyboardTop < viewBottom {
            inset = viewBottom - keyboardTop
        } else {
            inset = 0.0
        }
        if (KeyboardAvoider.logTransitions) {
            NSLog("did show, view.bottom: %.1f, keyboard.top: %.1f, inset: %.1f", viewBottom, keyboardTop, inset)
        }
        self.delegate?.inset(by: inset, keyboardAvoider: self)
    }

    @objc func keyboardWillHide(note: Notification) {
        if (KeyboardAvoider.logTransitions) {
            NSLog("did hide, inset: 0.0")
        }
        self.delegate?.inset(by: 0.0, keyboardAvoider: self)
    }
}

protocol KeyboardAvoiderDelegate : AnyObject {
    func inset(by inset: CGFloat, keyboardAvoider: KeyboardAvoider)
}