Ionic: Keyboard overlaps a focused text input on iOS 11 - javascript

Issue
When I click the text input from the modal, a keyboard overlaps the text input. This issue has found during testing on iPhone SE (iOS 11) device.
I've looked up a several threads and tried to figure out on my own, but I've realized that my current problem has been a chronic issue for Ionic developers until now.
These are the related links to my issue. I've tried given solutions from links below, but none of them worked with my code.
Keyboard issue
Keyboard overlaps the text input when the input is placed inside an ion-footer
Keyboard hides input until I start typing
Ionic 2 On-Screen Keyboard Covers Focused Input Element Inside Grid Component
Version Info
cli packages: (/usr/local/lib/node_modules)
#ionic/cli-utils : 1.19.0
ionic (Ionic CLI) : 3.19.0
global packages:
cordova (Cordova CLI) : 7.1.0
local packages:
#ionic/app-scripts : 3.1.4
Cordova Platforms : android 6.3.0 ios 4.5.4
Ionic Framework : ionic-angular 3.9.2
System:
ios-deploy : 1.9.2
Node : v8.9.0
npm : 5.5.1
OS : macOS High Sierra
Xcode : Xcode 9.2 Build version 9C40b
Expected behavior
Ion input should stay in a position right above the keyboard while a user types some messages.
Actual behavior
app.component.ts
I've included keyboard.disableScroll(true); inside platform.ready() to prevent navbar crashing issue. Without this line of code, the keyboard works fine with the input text. But it pushes the whole content to the top including navbar, thus for the first few messages appear to be hidden.
Any ideas?
UPDATED
I'm not sure the way I've solved the issue is the best solution, but for now, I replaced the content and footer's margin-bottom with a sum of an initial height of text area and the keyboard height.
If you have a better solution, feel free to leave it as an answer.
Here's the final result.

I was having similar problems in a similar project setup where the keyboard in iOS overlapped the footer bar in ionic. I was able to solve it by removing the ionic-plugin-keyboard#2.2.1 and adding cordova-plugin-ionic-keyboard#2.0.5 https://github.com/ionic-team/cordova-plugin-ionic-keyboard
Apparently I didn't notice that ionic-plugin-keyboard was deprecated as I was upgrading my project from Ionic 1 to 2, I'm guessing you may have been in a similar position.

To make things happen, first, you need to get the height of three elements like the example code below. For example,
#ViewChild(Content) content: Content;
ionViewDidLoad() {
if (this.platform.is('ios'))
this.addKeyboardListeners();
this.scrollContentElement = this.content.getScrollElement();
this.footerElement = document.getElementsByTagName('your page component')[0].getElementsByTagName('ion-footer')[0];
this.inputElement = document.getElementsByTagName('your page component')[0].getElementsByTagName('textarea')[0];
}
Then, add a keyboard listener for ios platform.
addKeyboardListeners() {
this.keyboardHideSub = this.keyboard.onKeyboardHide().subscribe(() => {
let marginBottom = this.textareaHeight - this.initialTextAreaHeight + 44;
this.renderer.setElementStyle(this.scrollContentElement, 'marginBottom', marginBottom + 'px');
this.renderer.setElementStyle(this.footerElement, 'marginBottom', '0px')
});
this.keybaordShowSub = this.keyboard.onKeyboardShow().subscribe((e) => {
let newHeight = (e['keyboardHeight']) + this.textareaHeight - this.initialTextAreaHeight;
let marginBottom = newHeight + 44 + 'px';
this.renderer.setElementStyle(this.scrollContentElement, 'marginBottom', marginBottom);
this.renderer.setElementStyle(this.footerElement, 'marginBottom', e['keyboardHeight'] + 'px');
this.updateScroll(250);
});
}
Lastly, it is important to unsubscribe the keyboard listeners whenever you leave the page.
Make it as a method and call it from wherever you need to.
removeKeyboardListeners() {
this.keyboardHideSub.unsubscribe();
this.keybaordShowSub.unsubscribe();
}

The solution of #coderroggie saved my life!
Just uninstall ionic-plugin-keyboard and then install cordova-plugin-ionic-keyboard and it will work.
In my case I had two windows:
- Chat List with ion-footer with input: when the input has focus the keyboard pushed all content up (including navbar).
Search with top searchbar and autocomplete List: when searchbar has focus the keyboard overlap the list.
Thank you #coderroggie.

It looks that this is framework related issue. I was also facing the same in android. To fix this i have used keyboard plugin and it's functions to handle height of viewport. Below is the code-
constructor(
private platform: Platform,
private keyboard: Keyboard
) {
if(this.platform.is('android')){
this.keyboard.onKeyboardShow().subscribe((e) => {
var keyboardHeight = e.keyboardHeight;
if ($("html").hasClass("plt-android")) {
keyboardHeight = keyboardHeight ? keyboardHeight : '337';
****337 is default height to handle if keyboard height not available****
$('body').css('height', 'calc(100vh - ' + keyboardHeight + 'px)' );
}
});
this.keyboard.onKeyboardHide().subscribe(e => {
$('input, textarea').blur();
if ($("html").hasClass("plt-android")) {
$("body").css("height", "100vh");
}
});
}
}
library--
npm install jquery
npm install #types/jquery
ionic cordova plugin add cordova-plugin-ionic-keyboard
npm install #ionic-native/keyboard
imports--
import { Platform } from '#ionic/angular';
import * as $ from "jquery";
import { Keyboard } from '#ionic-native/keyboard/ngx';

I've changed
<ion-input type="tel" pattern="tel" autocomplete="tel (ionChange)="writeValue($event.target.value)"></ion-input>
to
<input type="tel" (change)="writeValue($event.target.value)" autocomplete="tel">
And added some styles
input {
width: 100%;
background-color: transparent;
border: none;
font-size: 17px;
font-weight: 400;
}
input:focus {
outline: none;
}

Finally, we got the perfect solution.
window.scrollBy(0, 100); // Scroll 100px downwards
window.scrollBy(100, 0); // Scroll 100px to the right

Related

Detect Android soft navigation bar height in Ionic 2

In my Ionic 2 application, I have a grid component with items, that scrolls vertically.
The problem is that in Android devices with soft navigation bar (included in the screen) The scrolling stops before the entire content has revealed (see the bottom of the screen).
Example screenshot of an Android Nexus 5 (with soft bottom navigation bar):
Example screenshot of an iPhone 7 (without soft bottom navigation bar):
My question is: How can I detect the soft navigation bar's height (if existent) so that I can add it to the grid's bottom padding?
Adding to Paul's answer in case someone else is having this issue:
You can get the height of the soft navigation bar using the original answer, and then inject that as a CSS variable and use it directly in your style:
ngOnInit(){
this.platform.ready().then(() => {
this.checkSoftButton();
});
}
private checkSoftButton(){
const softButton=(screen.height - this.platform.height());
const body:any=document.querySelectorAll('body');
body.forEach((e:any)=>{
e.classList.add('soft-button');
e.style= '--ion-soft-button:' + softButton + 'px';
});
}
You can do this once in the first component and then use it in your style like
height:calc(100% - var(--ion-soft-button));
or
height:calc(100vh - var(--ion-soft-button));
You can even use the soft-button class added to the body in case you need to perform another operation inside your app if there is a soft button.
Try to use Cordova Fullscreen Plugin or add the below settings in your config file,
<preference name="Fullscreen" value="true" />
Answer:
We can use the global screen object, in order to get the dimensions of the entire screen, and the normal platform.height() to get the dimensions if the window (without the soft navigation bar's height).
Sample method:
/**
* On some Android devices there is a soft navigation bar,
* which overlaps with the screen.
* For that reason, we need to compute an extra space for
* the drawer so that the items in the last
* row are not shown "behind" the navigation bar
* #returns {number} the difference in pixels.
*/
getMarginBottomPropertyForDrawer() {
const difference = screen.height - this.platform.height();
return difference;
}
Another solution would be the following:
document.addEventListener('deviceready', () => {
var initialHeight = document.documentElement.clientHeight;
window.addEventListener('resize', resizeFunction);
function resizeFunction() {
console.log('STATUS BAR HEIGHT', document.documentElement.clientHeight - initialHeight);
window.removeEventListener('resize', resizeFunction);
}
StatusBar.overlaysWebView(true);
});
It takes about 150ms from deviceready, which you can "hide" by showing the SplashScreen a bit longer :)

Cordova camera resize on orientation change

When taking a photo via navigator.camera.getPicture and changing the device's orientation inside the photo interface, the webview's viewport doesn't resize upon returning. The blank space is not part of the HTML document, so internal resizing in the app doesn't help.
A plugin bug? Is there a way to force resizing on the cordova / webview layer?
That's the result of starting vertical, opening the photo interface, turning into horizontal and returning to the app:
Dirty fix after returning from the camera interface:
fixCordovaCameraBug: function() {
if (... == 'iOS') {
var actions = window.StatusBar.isVisible ? ['hide', 'show'] : ['show', 'hide'];
window.StatusBar[actions[0]]();
window.StatusBar[actions[1]]();
window.setTimeout(function() {
// framework specific
Ext.GlobalEvents.fireResize();
}, 1);
}
},
This was just fixed with cordova-plugin-statusbar#2.2.0

Nodewebkit app: hide cursor

I'm developing my web app with nodewebkit in fullscreen mode.
It has to be used with touchscreen monitor.
I've used CSS proprerty:
html * {
cursor: none;
}
In nodewebkit's manifest seems that nothing usefull is provided to remove cursor..
Problem is that cursor disappears only when it is moved the first time.
How can I improve this behavior?
I've fixed the problem calling from script:
document.body.style.cursor = 'none';
But I can't understand why doesn't work from css.
I think maybe you need to focus window at first to make the css hiding cursor work?!
I meet the same issue and then have gone with the following code.
var gui = require("nw.gui");
var win = gui.Window.get();
win.focus();

Cordova/Phonegap 3.1 keyboard (still) overlays focused form fields - iOS 7

I just upgraded from cordova 3.0 to 3.1 and I'm still experiencing a very disturbing issue (which still exists when playing with KeyboardShrinksView preference).
Whenever I'm focusing an element (input/textarea) which triggers the keyboard opening, the element gets hidden behind the keyboard and I need to scroll down (using webkit-overflow-scrolling for scrolling by the way) in order to see the element and its content.
When KeyboardShrinksView is set to true the page won't even scroll, making it even worse.
Any solutions in order to fix this issue? I've seen a few questions and bug reports but with no working solutions (or solutions at all).
Playing with the "fullscreen" preference won't solve the problem.
Just had a very similar problem to this. Some of the hacks found on this site did work, but had nasty side effects (such as making a mess of scrolling or CSS layout). Finally came up with a brand new stupid hack.
Viewport meta tag:
<meta name="viewport" content="initial-scale=1, maximum-scale=1, width=device-width" />
JavaScript run after load:
document.body.style.height = screen.availHeight + 'px';
And that's it. Works on iOS 7 and I have no idea why.
Finally fixed the problem with the help of the following plugin: jQuery scrollTo plugin
Whenever i'm focusing on an element i'm triggering a focus event which does the following calculations and updates the scroll position:
updateScroll: function(e){
var el = $(e.currentTarget);
var offset = -$(".scrollerWrap").height() + $(el).height();
$(".scrollerWrap").scrollTo(el,{offset: offset});
}
Sticks the bottom of the input/textarea to the top of the keyboard. Works like a charm, even if the solution needs to go through that bit of JavaScript.
Well, logically the view should move up when the keyboard opens. I have faced a similar issue with iOS7 and to fix it I have applied few css tweaks.
Tweaks were applied on the wrapper class/id which is containing the content of the app.
position: relative;
overflow: hidden;
height: 460px;
width: 320px;
Note - Height and width are judged dynamically depending on the device height and width
height = window.innerHeight
width = window.innerWidth
By using jQuery selectors height and width are appended to wrapping class/id.
Works for me.
document.body.style.height = (screen.availHeight - 100) + 'px';
I think the issue here originates from Framework7.
document.body.style.height = window.outerHeight + 'px';
The above code placed in my index.js file worked like charm.

Feature detection for position: fixed

I am trying to find a script that detects if a device places position: fixed elements relative to the ViewPort and not to the entire document.
Currently, standard desktop browsers and Mobile Safari (for iOS 5) do so, whereas Android devices place the fixed elements relative to the entire document.
I have found a couple of tests to detect this, but none of the seem to work:
http://kangax.github.com/cft/ Gives me a false positive when I pass it from an Android device.
https://gist.github.com/1221602 Gives me a false negative when I pass it in an iPhone with iOS 5.
Does anybody know where to find / how to write a test that actually detects that? I don't want to rely on browser sniffing.
According to the contributors at Modernizr, you cannot do this without detecting the browser in use. The contributors are quite well-established in the field.
Testing for position: fixed on iOS and Android devices is listed under the Undetectables wiki page in the Modernizr project.
The MobileHTML5 website lists the support for position:fixed. http://mobilehtml5.org/
Actually, the guys from the Filament Group did a smart thing with their Fixedfixed putting the user agent string of known false positives in their test.
Check it # http://github.com/filamentgroup/fixed-fixed
Someone could complete it with some false negatives too, and make it a modernizr aditional featur test.
I've created another check if position:fixed is really supported in browser. It creates fixed div and try to scroll and check if the position of div changed.
function isPositionFixedSupported(){
var el = jQuery("<div id='fixed_test' style='position:fixed;top:1px;width:1px;height:1px;'></div>");
el.appendTo("body");
var prevScrollTop = jQuery(document).scrollTop();
var expectedResult = 1+prevScrollTop;
var scrollChanged = false;
//simulate scrolling
if (prevScrollTop === 0) {
window.scrollTo(0, 1);
expectedResult = 2;
scrollChanged = true;
}
//check position of div
suppoorted = (el.offset().top === expectedResult);
if (scrollChanged) {
window.scrollTo(0, prevScrollTop);
}
el.remove();
return suppoorted;
}
This function was tested in Firefox 22, Chrome 28, IE 7-10, Android Browser 2.3.

Categories

Resources