Detect events from inside a WKWebView instance - ios

I know how to detect a normal keyboard being shown in Swift but I'm wondering if it's possible to detect the events inside a WKWebView because... if the app gets in the background, inputs lose focus but the "blur" event isn't triggered.
The idea is that I have a "navigation bar" in the app which gets pushed out of the view (upwards) when the keyboard is being shown, and I'd like to keep showing it. Knowing the keyboard is about 216px tall I'd just like to narrow the height of the content wrapper which is flex based by 216px but that's not really working since it is an animation which I can't really reproduce so it's smooth. I also can't detect when user went into emoji tab. I got rid of the autocorrect since I just set it to off for the input tag.

Try this code.
override viewWillAppear(){
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil);
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide"), name:UIKeyboardWillHideNotification, object: nil);
}
func keyboardWillHide(){
navigationController?.setNavigationBarHidden(false, animated: true)
}
func keyboardWillShow(notification: NSNotification) {
navigationController?.setNavigationBarHidden(true, animated: true)
var info = notification.userInfo!
var keyboardFrame: CGRect = (info[UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue()
// handle your layout according to frame
}

Related

Keyboard will show notification called when keyboard is not present for AccessoryInputView

I have an input accessory view called chatBoxView, which contains a custom growingTextView and couple of buttons to send the message. And this inputAccessoryView is setup in my main view controller.
override var inputAccessoryView: UIView? {
get {
return chatBoxView
}
}
override var canBecomeFirstResponder: Bool {
return true
}
So every time I go to this viewController, I see the chatBoxView at the bottom of my screen, which is wanted. However, the keyboard isn't visible yet (only the chatBoxView), but why does my KeyBoardWillShow notification keep getting called?
Also, when the keyboard is up, then disappears when I tap the outside, KeyboardWillDisappear function gets called, but KeyBoardWillShow function gets called right after.
Here are the function for the Keyboard notifications.
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)
}
#objc func keyboardWillShow(notification: Notification) {
if let keyboardHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
print("Notification: Keyboard will show")
DispatchQueue.main.async {
self.tableView.setBottomInset(to: keyboardHeight - self.chatBoxView.frame.height)
self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .bottom, animated: true)
}
}
}
#objc func keyboardWillHide(notification: Notification) {
print("Notification: Keyboard will hide")
tableView.setBottomInset(to: 0.0)
}
So basically, I get the log "Notification: Keyboard will show", when the keyboard isn't showing and only the accessory view. Any ideas?
The problem is that you are throwing away important information in the UIResponder.keyboardFrameEndUserInfoKey. It is not enough just to look at the keyboard's height. You need to look at where the keyboard will be — look at its entire frame information. If the top of the keyboard is not going to be above the bottom of the screen, clearly you should not be doing anything. Similarly, if the keyboard frame is not going to be changing from where it was, you should not be doing anything.
In simulator, make sure you show software keyboard.
Click here or ⌘ + K

Looking for 2 keyboard observers. 1 that gets triggered when the keyboard is about to show and 1 that only gets triggered when the keyboard is hiding

I am mutating a constraint when a keyboard is showing and hiding on the screen so that some text can be displayed at the bottom of the view. I instantiated 2 property observers, keyboardWillShowNotification and keyboardWillHideNotification. When the app initially starts and I pull up a keyboard, keyboardWillShowNotification is triggered as expected, but when I hide the keyboard, both keyboardWillHideNotification and keyboardWillShowNotification are triggered which has caused some unexpected behavior with toggling the bottom constraint.
Is there a keyboard observer combo where one observer only gets triggered when the keyboard is about to show and the other observer only gets triggered when the keyboard is hiding?
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil) { (notification) in
print("show")
}
notificationCenter.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: nil) { (notification) in
print("hide")
}
}
}
I've seen that bug. What I do is bail out of either notification handler if the frame is not actually going to change:
let d = notification.userInfo!
let beginning = d[UIResponder.keyboardFrameBeginUserInfoKey] as! CGRect
let ending = d[UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
if beginning == ending {return}

Why does the view auto animate?

I have this code in a UIViewController that changes the height of the view when the keyboard opens.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
// Subscribe to keyboard events.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
let keyboardHeight = notification.userInfo![UIKeyboardFrameEndUserInfoKey]!.CGRectValue.height
// UIView.animateWithDuration(0.5) {
self.view.frame.size.height -= keyboardHeight
self.view.layoutIfNeeded()
// }
}
I notice that the view animates even without UIView.animateWithDuration. Why is this so?
The notification is send out as part of an animation block. If you extract the information from the notification related to the animation, you can have other views animate alongside with it. In your case, all the changes to any view you make between keyboardWillShow and keyboardDidShow are going to be animated as part of that keyboard-animation.

(Swift) Moving views out of the way for keyboard?

I am having a weird problem with moving my views to make room for an incoming keyboard. Basically, in my app, there is a button that performs a segue which pushes a new instance of a view controller that is embedded inside of a navigation controller modally. Within this first instance, my keyboard code works perfectly. The code is as follows:
func keyboardWillShow(sender: NSNotification) {
if !keyBoard {
self.view.frame.origin.y -= 200
}
keyBoard = true
}
func keyboardWillHide(sender: NSNotification) {
if keyBoard {
self.view.frame.origin.y += 200
}
keyBoard = false
}
with the following in viewDidLoad:
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
I also added a tapGestureRecognizer so that when the keyboard is showing and the user taps anywhere on the screen, the keyboard closes:
let tapped = UITapGestureRecognizer(target: self, action: "closeKeyboard")
tapped.numberOfTapsRequired = 1
self.view.addGestureRecognizer(tapped)
and
func closeKeyboard() {
self.view.endEditing(true)
}
So in the first instance, this code works perfectly. However, after I go back, calling self.dismissViewControllerAnimated, and, once I am on the original screen, click the button that calls performSegue again and push a new instance of this same view controller, the code breaks and the view no longer moves out of the way of the keyboard but just sort of stutters and bounces a little. I have no idea why this is happening and any help would be very much appreciated. Thanks!
Try putting a breakpoint on keyboardWillShow and keyboardWillHide, and tell me if both the methods are called when you go back to the second ViewController.

Keyboard size changed event in swift?

I am aware of the keyboardWillShow and the keyboardWillHide events by:
override public func viewWillAppear(animated: Bool) {
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil)
}
But with the new keyboards in iOS8 the keyboard is able to change without dismissing the keyboard and I was wondering how to call a function on keyboard size change. Anyone know? Thanks.
Edit: It is now calling on frame change but using this code:
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() {
NSLog("\(keyboardSize.height)")
}
It returns the old keyboard height for example when the frame changes to "224.0" it returns "253.0" as if the height has not updated by time the code is called, and when it goes have to "253.0" it returns the old height again which is "224.0"
Edit 2:
Instead of using "UIKeyboardFrameBeginUserInfoKey", I used "UIKeyboardFrameEndUserInfoKey" and it is now working.
You want UIKeyboardWillChangeFrameNotification and/or UIKeyboardDidChangeFrameNotification.
See the documentation of UIWindow for all of the keyboard related notifications.

Resources