Created
October 5, 2017 15:20
-
-
Save agiletortoise/82e5e378e3483ab835db49aefed300e3 to your computer and use it in GitHub Desktop.
How to update input accessory view to handle iPhone X with external keyboard
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ViewController.swift | |
// TEST_InputViewX | |
// | |
// Created by Greg Pierce on 10/5/17. | |
// Copyright © 2017 Agile Tortoise. All rights reserved. | |
// | |
// Demonstrates how to update an input accessory view | |
// to work on iPhone X with external keyboard attached | |
// using safe area insets. | |
// | |
// This adds the necessary padding under the input accessory | |
// So it's not clipped by home button area. | |
import UIKit | |
class ViewController: UIViewController, UITextViewDelegate { | |
struct Constants { | |
static let AccessoryViewHeight: CGFloat = 44.0 | |
} | |
@IBOutlet weak var textView: UITextView! | |
var accessoryView: UIView? | |
override func viewDidLoad() { | |
super.viewDidLoad() | |
// observe keyboard events | |
let nc = NotificationCenter.default | |
nc.addObserver(self, selector: #selector(keyboardDidShow(_:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil) | |
nc.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) | |
nc.addObserver(self, selector: #selector(keyboardWillChangeFrame(_:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) | |
} | |
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { | |
buildInputView() | |
textView.inputAccessoryView = accessoryView | |
return true | |
} | |
func buildInputView() { | |
// create input accessory view | |
guard accessoryView == nil else { return } | |
let accView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: self.view.bounds.size.width, height: Constants.AccessoryViewHeight)) | |
accView.autoresizingMask = [.flexibleHeight] // important! allows it to resize | |
accView.backgroundColor = .red | |
// create a nested content view for your actual input controls | |
let contentView = UIView(frame: .zero) | |
contentView.backgroundColor = .green | |
// constrain content view to safe area of parent view | |
contentView.translatesAutoresizingMaskIntoConstraints = false | |
accView.addSubview(contentView) | |
contentView.leadingAnchor.constraint(equalTo: accView.safeAreaLayoutGuide.leadingAnchor).isActive = true | |
contentView.trailingAnchor.constraint(equalTo: accView.safeAreaLayoutGuide.trailingAnchor).isActive = true | |
contentView.topAnchor.constraint(equalTo: accView.safeAreaLayoutGuide.topAnchor).isActive = true | |
contentView.heightAnchor.constraint(equalToConstant: Constants.AccessoryViewHeight).isActive = true | |
accessoryView = accView | |
} | |
func updateInputViewFrame() { | |
guard let accView = accessoryView else { return } | |
// calculate the accessory view height based on safe insets | |
let newHeight = accView.safeAreaInsets.bottom + Constants.AccessoryViewHeight | |
if newHeight != accView.frame.size.height { | |
accView.frame = CGRect(x: 0.0, y: 0.0, width: self.view.bounds.size.width, height: newHeight) | |
textView.reloadInputViews() | |
} | |
} | |
@objc func keyboardDidShow(_ note: NSNotification) { | |
// update height of accessory view if needed | |
updateInputViewFrame() | |
} | |
@objc func keyboardWillChangeFrame(_ note: NSNotification) { | |
// update height of accessory view if needed | |
updateInputViewFrame() | |
} | |
@objc func keyboardWillHide(_ note: NSNotification) { | |
} | |
@IBAction func hideKeyboard(_ sender: Any) { | |
textView.resignFirstResponder() | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks! The
if newHeight != accView.frame.size.height {
seems to be pretty important, otherwise the device will get stuck in an endless cycle ofkeyboardDidShow
getting called.