I want to have a View with a textField an a send button above my keyboard, when the keyboard is shown. But this doesn't work.
I already implemented this in my code:
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_ :)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tabBarController?.tabBar.isHidden = true
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
tabBarController?.tabBar.isHidden = false
}
// MARK: - Keyboard stuff
#objc func keyboardWillShow(_ notification: NSNotification) {
let keyboardFrame = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as AnyObject).cgRectValue
print("hier ist \(keyboardFrame!)")
UIView.animate(withDuration: 0.1) {
self.bottomConstraint.constant = keyboardFrame!.height
self.view.layoutIfNeeded()
}
}
#objc func keyboardWillHide(_ notification: NSNotification) {
UIView.animate(withDuration: 0.1) {
self.bottomConstraint.constant = 0
self.view.layoutIfNeeded()
}
}
Check out textField inputAccessoryView. There's a tutorial here that explains what you're trying to do.
Related
I have searched as many posts as I found and still I cannot solve the problem. Please keep in mind that I have tried all the solutions provided that I have found and still when the keyboard appears the table does not scroll up, nor does it adjust its content view. The table v.c. is a child of a v.c., it is being pushed by the nav con (modal also does not work), below all of this sits a tab bar controller. Below is the code which I consider to be relevant.
Code inside the v.c.:
override func viewDidLoad() {
super.viewDidLoad()
safeGuide = self.view.safeAreaLayoutGuide
view.backgroundColor = UIColor.customColoursForAllElements(colourName: "background blue")
programMainMenu = self.tabBarController as? ProgramMainMenu
setTopViews()
let msgsArea = ChatMsgsAreaTVC(typeForCurrentInstance: .singleChat(otherMemberName: self.otherMemberName), userUID: self.userUID, searchResultMsg: msgSelectedInSearch != nil ? msgSelectedInSearch : nil, searchTxt: self.searchTxt)
msgsArea.valuesForSingleChat = chatDetails
displayChild(controller: msgsArea)
}
fileprivate func displayChild(controller: UIViewController) {
self.addChild(controller)
self.view.addSubview(controller.view)
controller.view.translatesAutoresizingMaskIntoConstraints = false
let childConstraints = [
controller.view.topAnchor.constraint(equalTo: detailsContainer.bottomAnchor, constant: 10),
controller.view.bottomAnchor.constraint(equalTo: safeGuide.bottomAnchor, constant: -55),
controller.view.leadingAnchor.constraint(equalTo: backBtn.leadingAnchor),
controller.view.trailingAnchor.constraint(equalTo: optionBtn.trailingAnchor)
]
NSLayoutConstraint.activate(childConstraints)
controller.didMove(toParent: self)
}
the code below is from the child table view controller:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardDidHide), name: UIResponder.keyboardDidHideNotification, object: nil)
configureMsgsTable()
observeAudioRecAccess()
setupAudioRecorder()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.resignFirstResponder()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.async {self.becomeFirstResponder()}
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
override var canBecomeFirstResponder: Bool {return true}
override var canResignFirstResponder: Bool {return true}
#objc func keyboardWillShow(notification: Notification) {
// note: changing the content size of the table does not work at all.
}
#objc fileprivate func keyboardDidHide() {
if !bypassForSetup {bypassForSetup = true}
else {
if msgTxtArea.isFirstResponder {msgTxtArea.resignFirstResponder()}
if addFileToMsgBtn.isSelected {addFileToMsgBtn.isSelected = false; addFileToMsgBtn.resignFirstResponder(); alterFileToMsgBtn(selected: false)}
}
}
fileprivate func configureMsgsTable() {
tableView.contentInsetAdjustmentBehavior = .always
tableView.backgroundColor = .clear
tableView.keyboardDismissMode = .interactive
tableView.separatorStyle = .none
tableView.showsVerticalScrollIndicator = false
tableView.estimatedRowHeight = 100
tableView.sectionFooterHeight = 0.0
tableView.scrollsToTop = false
tableView.setBottomInset(to: -15)
}
I also have a custom input accessory view that I have not included in this code.
I have textField and textView in the table. When editing textFiled, this code works and all text fields rise above the keyboard. When I edit a textView, nothing happens. It will help to edit the code so that for textView this code also works. Please do not offer third-party libraries. Thanks
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow(_:)),
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillHide(_:)),
name: UIResponder.keyboardWillHideNotification,
object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
}
#objc
fileprivate func keyboardWillShow(_ notification: Notification) {
let keyboardFrame = ((notification as NSNotification).userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? CGRect.zero
let contentInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardFrame.height, right: 0.0)
self.tableView.contentInset = contentInsets
self.tableView.scrollIndicatorInsets = contentInsets
UIView.animate(withDuration: 0.25) {
self.tableView.layoutIfNeeded()
self.view.layoutIfNeeded()
}
}
#objc
fileprivate func keyboardWillHide(_ notification: Notification) {
tableView.contentInset = .zero
}
yes you can!
all you need to do is knowing where you textfield position,
then set your scroll Offset
write this :
NotificationCenter.default.addObserver(self, selector: #selector(yourMethod(_:)), name: UITextField.textDidBeginEditingNotification, object: nil)
and your function
#objc func yourMethod(_ sender: NSNotification) {
if let tfActive = sender.object as? UITextField {
let frameRelatedToSuper = tfActive.convert(yourScrollView.contentOffset, to: nil)
//[mockTF convertPoint:self.parentScrollView.contentOffset toView:nil];
yourScrollView.setContentOffset(frameRelatedToSuper, animated: true)
}
}
the rest is your logic.
good luck
note: without adding additional height it might stopped on the top of your textfield
you can declare this
var padding: CGFloat = 10
padding = yourTF.bounds.height + padding
frameRelatedToSuper += padding
edit : the rest is your logic what i meant was ,because you need to calculate your keyboard height and add to framerelatedtosuper
import UIKit
class KeyboardViewController: UIInputViewController {
var heightKeyboard : CGFloat?
#IBOutlet var nextKeyboardButton: UIButton!
override func updateViewConstraints() {
super.updateViewConstraints()
// Add custom view sizing constraints here
}
override func viewDidLoad() {
super.viewDidLoad()
// Perform custom UI setup here
self.nextKeyboardButton = UIButton(type: .system)
self.nextKeyboardButton.setTitle(NSLocalizedString("Next Keyboard", comment: "Title for 'Next Keyboard' button"), for: [])
self.nextKeyboardButton.sizeToFit()
self.nextKeyboardButton.translatesAutoresizingMaskIntoConstraints = false
self.nextKeyboardButton.addTarget(self, action: #selector(handleInputModeList(from:with:)), for: .allTouchEvents)
self.view.addSubview(self.nextKeyboardButton)
self.nextKeyboardButton.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
self.nextKeyboardButton.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillDisappear), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillAppear(notification:)), name: UIResponder.keyboardDidShowNotification, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillAppear(true)
NotificationCenter.default.removeObserver(self)
}
#objc func keyboardWillAppear(notification: NSNotification) {
//Do something here
print("keyboardWillAppear()")
print("keyboardShown")
if let infoKey = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey],let rawFrame = (infoKey as AnyObject).cgRectValue {
let keyboardFrame = view.convert(rawFrame, from: nil)
self.heightKeyboard = keyboardFrame.size.height
print(self.heightKeyboard)
}
}
#objc func keyboardWillDisappear() {
print("keyboardWillDisappear()")
}
override func viewWillLayoutSubviews() {
self.nextKeyboardButton.isHidden = !self.needsInputModeSwitchKey
super.viewWillLayoutSubviews()
}
override func textWillChange(_ textInput: UITextInput?) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(_ textInput: UITextInput?) {
// The app has just changed the document's contents, the document context has been updated.
var textColor: UIColor
let proxy = self.textDocumentProxy
if proxy.keyboardAppearance == UIKeyboardAppearance.dark {
textColor = UIColor.white
} else {
textColor = UIColor.black
}
self.nextKeyboardButton.setTitleColor(textColor, for: [])
}
}
I am creating Keyboard Extension (swift) But unable to get height of keyboard . I am using storyboard for keyboard creation. func keyboardWillAppear(),func keyboardWillDisappear() never getting called.
So unable to get keyboard size based on different sizes and orientation
If I try to tap into my textfields I get an error, related to these few lines of code that try to get the size of the keyboard on a mobile ios device. The Notification Center lines of code are inside the overriding ViewDidAppear.
NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillShow:")), name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: Selector(("keyboardWillHide:")), name: UIResponder.keyboardDidHideNotification, object: nil)
func keyboardWillShow(notification: NSNotification) {
if let userInfo = notification.userInfo {
if let keyboardSize = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
self.bottomConstraint.constant = keyboardSize.height
}
}
}
func keyboardWillHide(notification: NSNotification) {
self.bottomConstraint.constant = 0
}
Use the type safe syntax
#selector(keyboardWillShow)
and
#objc func keyboardWillShow(_ notification: Notification) { ...
However I highly recommend to use the modern closure based syntax
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { [weak self] notification in
if let userInfo = notification.userInfo,
let keyboardSize = (userInfo[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
self?.bottomConstraint.constant = keyboardSize.height
}
}
NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { [weak self] _ in
self?.bottomConstraint.constant = 0
}
Try Following code :
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
#objc func keyboardWillShow(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
print("notification: Keyboard will show")
}
}
#objc func keyboardWillHide(notification: Notification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
}
}
You can try this:
This code in viewDidLoad():
// Do any additional setup after loading the view.
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
and then add this in ViewController
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
print("Keyboard opened \(keyboardSize)")
}
}
#objc func keyboardWillHide(notification: NSNotification) {
print("Keyboard hide")
}
Hope this will help.
You should deregister any notification you register in a view.
func registerForKeyboardNotifications()
{
//Adding notifies on keyboard appearing
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
func deRegisterFromKeyboardNotifications()
{
//Removing notifies on keyboard appearing
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
}
#objc func keyboardWasShown(_ notification: NSNotification)
{
//todo
}
#objc func keyboardWillBeHidden(_ notification: NSNotification)
{
//todo
}
override func viewDidLoad() {
super.viewDidLoad()
registerForKeyboardNotifications()
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
deRegisterFromKeyboardNotifications()
}
You've got this error because of notification parameter. With current signature you should use:
#selector(keyboardWillShow(notification:))
#selector(keyboardWillHide(notification:))
Or rewrite your methods in that way:
#objc func keyboardWillShow(_ notification: Notification) {
// Code
}
#objc func keyboardWillHide(_ notification: Notification) {
// Code
}
And use the next syntax:
#selector(keyboardWillShow(_:))
#selector(keyboardWillHide(_:))
Edited:
You can also use simplified syntax:
#selector(keyboardWillShow)
#selector(keyboardWillHide)
Use like below code
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillShow(notification:)),
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(keyboardWillHide(notification:)),
name: UIResponder.keyboardWillHideNotification,
object: nil)
#objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
// Your code
}
}
#objc func keyboardWillHide(notification: NSNotification) {
// Your code
}
Hope this works, If any doubt plz comment.
I have a textview and a text field on my screen and I want move screen when edit textview.
This is my code
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: .UIKeyboardWillShow, object: nil)
// NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: .UIKeyboardWillHide, object: nil)
print("addd observer")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil)
// NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil)
}
#objc func keyboardWillShow(_ sender: Notification) {
let keyboardSize = (sender.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue
print("keyboardwillshow")
ksize = keyboardSize?.height
}
#objc func textViewDidBeginEditing(_ textView: UITextView) {
print("textviewedit")
boxview.frame.origin.y -= ksize
print("textview")
}
#objc func textViewDidEndEditing(_ textView: UITextView) {
print("textvieweditend")
boxview.frame.origin.y = 0
}
It works when I just edit textview. However, if I edit the textview right after focus on the textfield(without exit keyboard) it doens't work.
I already checked that textviewDidBeginEditing() is called but the screen doesn't move.. How can I solve this? All advises are welcome!
I add self.view.Layoutifneeded() to keyboardwillchange() and it works!! thanks everybody.