Portions of my app present users with forms via a webview. I've had a few users ask why after entering data into a field when they continue to scroll down the form/webview the keyboard remained visible on the screen. I cannot seem to find any textarea or textfield delegate method which would dismiss the keyboard.
I am apprehensive to start adding gesture recognizers because I don't want to override the touches on the webview.
Native behavior:
The Keyboard shows automatically on focus on an UITextView, to hide it again, you need to call yourself on the UIView [self.view endEditing:YES];
On the WKWebView the Keyboard also shows automatically on focus on an HTMLInputElement for example and hides on blur.
But the WKWebView does not blur the focus of the HTMLInputElement by tapping somewhere outside (e.g. on the body), so the Keyboard still stays in the view.
If you want to hide the Keyboard after some scrolling you could just go with a little JS (inject it just into the WKWebView):
var SKIP_BLURRING = ['INPUT', 'TEXTAREA'];
document.body.addEventListener('touchend', function (event) {
var activeElement = document.activeElement;
var tapped = event.target;
var shouldSkipElement = SKIP_BLURRING.indexOf(tapped.tagName) > -1;
var isSameElement = activeElement === tapped;
if (shouldSkipElement || isSameElement) {
return;
}
activeElement.blur();
}, false);
Related
Is there a way in Swift to force the iOS keyboard to not have the top part? By saying the top part I mean the autocomplete and the input field switcher tools that appear at the top.
Some of my views have embedded webViews that run local js and I want the keyboard for the inputs in webView to not have that top part of the keyboard. If it`s not possible to disable these for webView specifically, any other method should be fine as well.
Please take a look at this screenshot to see exactly what part of the keyboard I am talking about.
You can try running the below JS in the webview every time you load the web page
var textFields = document.getElementsByTagName('input');
if (textFields) {
var i;
for( i = 0; i < textFields.length; i++) {
var txtField = textFields[i];
if(txtField) {
txtField.setAttribute('autocomplete','off');
txtField.setAttribute('autocorrect','off');
txtField.setAttribute('autocapitalize','off');
txtField.setAttribute('spellcheck','false');
}
}
}
Additionally write this code to hide the done button accessory view from keyboard
class CustomWebView: WKWebView {
var accessoryView: UIView?
override var inputAccessoryView: UIView? {
return accessoryView
}
}
And use CustomWebView in place of WKWebView wherever this functionality is needed.
Let me know if you need any more help.
Happy Coding :)
I have a custom titleView with 2 custom UIButtons with arrow images that allow navigation to the next view controller in the paging structure. They work perfectly fine until a button is tapped within the WKWebView. Then they don't work anymore and the selector is not called. Note that other buttons in the nav bar still work (UIBarButtonItems). The buttons work properly again after the user swipes over to the next view controller.
After looking into it some, it looks like a WKCompositingView becomes first responder and if I override becomeFirstResponder() in a WKWebView subclass, the issue goes away. I'm still a little baffled though, and would like to understand the root of the problem.
class NonFirstRespondableWebView: WKWebView {
override func becomeFirstResponder() -> Bool {
return false
}
}
Does anyone have any insight into why this is happening?
Most UI elements in swift have a UIResponder. Unhandled events are passed up the responder chain to enclosing views. My guess is that the WKWebView is absorbing all touch events once the window has become active. You can learn more about the responder chain here
Regarding a first responder. From the docs:
The first responder is usually the first object in a responder chain to receive an event or action message. In most cases, the first responder is a view object that the user selects or activates with the mouse or keyboard.
Assuming you want to keep interactivity with the WKWebView fully functional (e.g. you need to bring up a keyboard or something), you can use
webView.resignFirstResponder()
To resign the responder at any time.
Otherwise, an extension that would give you the same functionality might look something like this:
extension WKWebView {
open override func becomeFirstResponder() -> Bool {
if self.superview?.superview is UIWebView {
return false
} else {
return super.becomeFirstResponder()
}
}
}
Here is my problem:
I have a first form that needs to be completed, once completed you can access the second form, it's an UIView that slide from the left to my view.
At the moment when I tap on one of the text fields of the second form, the position of the view got reseted and I have a view on the first form again.
Here is my code for sliding:
#IBAction func Postulate(sender: AnyObject) {
UIView .animateWithDuration(0.5, animations: { () -> Void in
self.formView.frame = CGRectMake(0, 64, 414, 736)
})
}
How can tapping on a textfield reset the view ? And how can I counter it ?
I tried to reslide the view with a duration of 0 when a textfield is tapped but it's not working.
Set the VC to be textField delegate then use the delegate method, textFieldBeganEditing or something like that to recognize when user tap on the text field.
class ClassName:UIViewController, UITextFieldDelegate {
#IBOutlet week var textField: UITextField! {
didSet { textField.delegate = self }
}
func textFieldDidBeginEditing(textField: UITextField){
//user tapped on the textField, do what you wanna do here
}
}
Well, finally I found a hack to bypass this.
I started the position of my second form view at 0 (on the view) and with the hidden state set as true. Then I make it slide to the left out of screen (being hidden) like this:
formView.hidden = true;
UIView .animateWithDuration(0, animations: { () -> Void in
self.formView.frame = CGRectMake(-425, 64, 414, 736)
})
When the button to go on my form view is pressed I put my form view hidden state to false and I make it slide to the right so the user can see it.
When I tap on the field, the position reset, but because the form view position was created in the view, it doesn't change.
Finally, when I click on my "return" button from the form view, I make it slide back to the left and make it's hidden state to true. With so on, when the user want to change anything on the first form, the positions are reseted, but the hidden state allow the user to see the form he wants to see and not the other.
Hope I helped someone.
THIS IS JUST A SWIFT HACK, this work, but it's probably not the best solution, if you have a better solution, give it so I can accept your answer.
My application is used with a barcode scanner connected via Bluetooth. When the scanner is connected you can double tap a button on the scanner to dismiss/show the on screen keyboard. 90% of the time the user will want the keyboard to be hidden as they will be scanning a barcode to input data. There are a few exceptions that I know of ahead of time that the keyboard will need to be enabled, I would like to save them the effort of pressing the scanner button to bring up the keyboard and instead force the keyboard to show up.
The scanner does not use resignfirstresponder to dismiss the keyboard, this is evident because the cursor is still visible and scanning a barcode will input data into the current text field.
Does anyone know how to dismiss/show the on screen keyboard without using resignfirstresponder?
For reference I am using this scanner http://ww1.socketmobile.com/products/bluetooth-scanners/how-to-buy/details.aspx?sku=CX2864-1336
To end editing completely in the view you can use the following
[self.view endEditing:YES];
This will remove the keyboard for you in the view.
For anyone still struggling with this, you can achieve this in Swift by making the inputView of the textfield equals UIView()
That is:
yourtextfield.inputview = UIView()
I ran into this today and have found a solution. The trick is to use a secondary text field that is off-screen or hidden with a custom empty inputView set and make that field become the first responder. That field captures text from the hardware scanner while the software keyboard hides.
However I got this working using a very similar approach and instead making the view controller itself the first responder as the scanning input view.
Example:
class SearchViewController: UIViewController, UIKeyInput {
let searchField = UITextField()
let softwareKeyboardHider = UIView()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(searchField)
inputAssistantItem.leadingBarButtonGroups = []
inputAssistantItem.trailingBarButtonGroups = []
}
override var canBecomeFirstResponder: Bool {
return true
}
override var inputView: UIView? {
return softwareKeyboardHider
}
var hasText: Bool {
return searchField.hasText
}
func insertText(_ text: String) {
searchField.insertText(text)
}
func deleteBackward() {
searchField.deleteBackward()
}
}
Now, when you want to hide the software keyboard make SearchViewController the first responder.
To show the software keyboard make SearchViewController.searchField the first responder.
In jQuery Mobile there are filtered listviews. After entering text into filter, list gets filtered but pressing GO button doesn't hide the keyboard.
User expects that keyboard will hide after pressing GO.
Is there any way to accomplish that?
You have to remove the focus manually from the input field with Javascript like this:
$('.ui-listview-filter .ui-input-text').live('keyup', function(event) {
if (event.keyCode == 13) {
// 'Go' pressed
$('.ui-listview-filter .ui-input-text').trigger('blur');
}
});
You may want to try changing the focus after the key is pressed. For example:
//this will un-select the text box, hiding keyboard
$('#searchInputId').blur();
//this will focus on something else, hiding keyboard
$('#somethingOtherThanTheSearch').focus();
Variant of Pablo's answer which works on my outdated version of jQuery (mobile):
// this is here to close the on-screen keyboards of mobile devices when the "go" button is used
$("input[data-type='search']").on('keyup', function(event) {
if (event.keyCode == 13) { // Enter or 'Go' pressed
event.target.blur(); // remove focus on the search field so keyboard goes away
}
});