fix(keyboard): android scroll stuck

When a state change happens, ensure the keyboard is hidden. When a
keyboard is hidden, ensure all pending timers our cleared. When
resetting scrollView, ensure it’s only doing it when it has to.
For testing: #1670 #2192
This commit is contained in:
Adam Bradley
2014-09-14 23:18:55 -05:00
parent b873190bc6
commit 74de015c22
4 changed files with 315 additions and 131 deletions

View File

@@ -30,6 +30,11 @@ function($rootScope, $state, $location, $document, $animate, $ionicPlatform, $io
$ionicViewService.disableRegisterByTagName('ion-side-menus');
}
// always reset the keyboard state when change stage
$rootScope.$on('$stateChangeStart', function(){
ionic.keyboard.hide();
});
$rootScope.$on('viewState.changeHistory', function(e, data) {
if(!data) return;

View File

@@ -66,6 +66,7 @@ var keyboardIsOpen;
var keyboardActiveElement;
var keyboardFocusOutTimer;
var keyboardFocusInTimer;
var keyboardPollHeightTimer;
var keyboardLastShow = 0;
var KEYBOARD_OPEN_CSS = 'keyboard-open';
@@ -75,6 +76,41 @@ ionic.keyboard = {
isOpen: false,
height: null,
landscape: false,
hide: function() {
clearTimeout(keyboardFocusInTimer);
clearTimeout(keyboardFocusOutTimer);
clearTimeout(keyboardPollHeightTimer);
console.log('keyboardHide');
ionic.keyboard.isOpen = false;
ionic.trigger('resetScrollView', {
target: keyboardActiveElement
}, true);
ionic.requestAnimationFrame(function(){
document.body.classList.remove(KEYBOARD_OPEN_CSS);
});
// the keyboard is gone now, remove the touchmove that disables native scroll
if (window.navigator.msPointerEnabled) {
document.removeEventListener("MSPointerMove", keyboardPreventDefault);
} else {
document.removeEventListener('touchmove', keyboardPreventDefault);
}
document.removeEventListener('keydown', keyboardOnKeyDown);
if( keyboardHasPlugin() ) {
cordova.plugins.Keyboard.close();
}
},
show: function() {
if( keyboardHasPlugin() ) {
cordova.plugins.Keyboard.show();
}
}
};
function keyboardInit() {
@@ -126,22 +162,23 @@ function keyboardSetShow(e) {
keyboardFocusInTimer = setTimeout(function(){
if ( keyboardLastShow + 350 > Date.now() ) return;
console.log('keyboardSetShow');
keyboardLastShow = Date.now();
var keyboardHeight;
var elementBounds = keyboardActiveElement.getBoundingClientRect();
var count = 0;
var pollKeyboardHeight = setInterval(function(){
keyboardPollHeightTimer = setInterval(function(){
keyboardHeight = keyboardGetHeight();
if (count > 10){
clearInterval(pollKeyboardHeight);
clearInterval(keyboardPollHeightTimer);
//waited long enough, just guess
keyboardHeight = 275;
}
if (keyboardHeight){
clearInterval(keyboardPollHeightTimer);
keyboardShow(e.target, elementBounds.top, elementBounds.bottom, keyboardViewportHeight, keyboardHeight);
clearInterval(pollKeyboardHeight);
}
count++;
@@ -192,28 +229,7 @@ function keyboardShow(element, elementTop, elementBottom, viewportHeight, keyboa
function keyboardFocusOut(e) {
clearTimeout(keyboardFocusOutTimer);
keyboardFocusOutTimer = setTimeout(keyboardHide, 350);
}
function keyboardHide() {
console.log('keyboardHide');
ionic.keyboard.isOpen = false;
ionic.trigger('resetScrollView', {
target: keyboardActiveElement
}, true);
ionic.requestAnimationFrame(function(){
document.body.classList.remove(KEYBOARD_OPEN_CSS);
});
// the keyboard is gone now, remove the touchmove that disables native scroll
if (window.navigator.msPointerEnabled) {
document.removeEventListener("MSPointerMove", keyboardPreventDefault);
} else {
document.removeEventListener('touchmove', keyboardPreventDefault);
}
document.removeEventListener('keydown', keyboardOnKeyDown);
keyboardFocusOutTimer = setTimeout(ionic.keyboard.hide, 350);
}
function keyboardUpdateViewportHeight() {

View File

@@ -687,11 +687,13 @@ ionic.views.Scroll = ionic.views.View.inherit({
self.resetScrollView = function(e) {
//return scrollview to original height once keyboard has hidden
self.isScrolledIntoView = false;
container.style.height = "";
container.style.overflow = "";
self.resize();
ionic.scroll.isScrolling = false;
if(self.isScrolledIntoView) {
self.isScrolledIntoView = false;
container.style.height = "";
container.style.overflow = "";
self.resize();
ionic.scroll.isScrolling = false;
}
};
//Broadcasted when keyboard is shown on some platforms.

View File

@@ -44,6 +44,9 @@
.scroll {
background: lightgreen;
}
.keyboard-open .scroll-content{
background: green;
}
input,
textarea {
@@ -56,136 +59,279 @@
<div id="logs" style="position:fixed; top:0; left:0; z-index:9999; background: #eee; font-size:8px; line-height:10px; display:block; "></div>
<ion-view id="view">
<ion-header-bar>
<label class="item item-input">
<span class="input-label">Header</span>
<input type="text" value="header input">
</label>
</ion-header-bar>
<ion-nav-view></ion-nav-view>
<ion-content class="padding">
<script id="input1.html" type="text/ng-template">
<form ng-submit="formSubmit()">
<ion-view id="view">
<ion-header-bar>
<div class="buttons">
<div class="list">
</div>
<h1 class="title">Input Tests</h1>
<div class="buttons">
<a class="button" href="#/input2">Page 2</a>
</div>
</ion-header-bar>
<label class="item item-input item-stacked-label">
<span class="input-label">Email</span>
<textarea>
Line 1
Line 2
Line 3
Line 4
Line 5
</textarea>
</label>
<ion-content class="padding">
<label class="item item-input">
<span class="input-label">Your Name</span>
<input type="text" value="name input" id="name">
</label>
<form ng-submit="formSubmit()">
<div class="item item-checkbox">
<span class="input-label">Remember me</span>
<label class="checkbox">
<input type="checkbox" id="remember-me">
<div class="list">
<label class="item item-input item-stacked-label">
<span class="input-label">Email</span>
<textarea>
Line 1
Line 2
Line 3
Line 4
Line 5
</textarea>
</label>
<label class="item item-input">
<span class="input-label">Your Name</span>
<input type="text" value="name input" id="name">
</label>
<div class="item item-checkbox">
<span class="input-label">Remember me</span>
<label class="checkbox">
<input type="checkbox" id="remember-me">
</label>
</div>
<label class="item item-input">
<span class="input-label">From 1</span>
<input type="text" value="from input" id="from1">
</label>
<label class="item item-input">
<span class="input-label">To 1</span>
<input type="text" value="to input" id="to1">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 1</span>
<textarea id="textarea" id="comment1">comment textarea</textarea>
</label>
<label class="item item-input">
<span class="input-label">From 2</span>
<input type="text" value="" id="from2">
</label>
<label class="item item-input">
<span class="input-label">To 2</span>
<input type="text" value="" id="to2">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 2</span>
<textarea id="textarea" id="comment2"></textarea>
</label>
<label class="item item-input">
<span class="input-label">From 3</span>
<input type="text" value="">
</label>
<label class="item item-input">
<span class="input-label">To 3</span>
<input type="text" value="">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 3</span>
<textarea id="textarea"></textarea>
</label>
<label class="item item-input">
<span class="input-label">From 4</span>
<input type="text" value="">
</label>
<label class="item item-input">
<span class="input-label">To 4</span>
<input type="text" value="">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 4</span>
<textarea id="textarea"></textarea>
</label>
<label class="item item-input">
<span class="input-label">From 5</span>
<input type="text" value="">
</label>
<label class="item item-input">
<span class="input-label">To 5</span>
<input type="text" value="">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 5</span>
<textarea id="textarea"></textarea>
</label>
<button type="button" class="button button-block button-energized" ng-click="openModal()">
Open Modal
</button>
<button type="submit" class="button button-block button-calm">
Submit!
</button>
</div>
</form>
<p>
<a href="clickTests.html">Click Tests</a> -
<a href="tapInputs.html">Tap Inputs</a> -
<a href="/test/">CSS Tests</a>
</p>
</ion-content>
</ion-view>
</script>
<script id="input2.html" type="text/ng-template">
<ion-view id="view">
<ion-header-bar>
<label class="item item-input">
<span class="input-label">From 1</span>
<input type="text" value="from input" id="from1">
<span class="input-label">Header</span>
<input type="text" value="header input">
</label>
</ion-header-bar>
<label class="item item-input">
<span class="input-label">To 1</span>
<input type="text" value="to input" id="to1">
</label>
<ion-content class="padding">
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 1</span>
<textarea id="textarea" id="comment1">comment textarea</textarea>
</label>
<form ng-submit="formSubmit()">
<label class="item item-input">
<span class="input-label">From 2</span>
<input type="text" value="" id="from2">
</label>
<div class="list">
<label class="item item-input">
<span class="input-label">To 2</span>
<input type="text" value="" id="to2">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Email</span>
<textarea>
Line 1
Line 2
Line 3
Line 4
Line 5
</textarea>
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 2</span>
<textarea id="textarea" id="comment2"></textarea>
</label>
<label class="item item-input">
<span class="input-label">Your Name</span>
<input type="text" value="name input" id="name">
</label>
<label class="item item-input">
<span class="input-label">From 3</span>
<input type="text" value="">
</label>
<div class="item item-checkbox">
<span class="input-label">Remember me</span>
<label class="checkbox">
<input type="checkbox" id="remember-me">
</label>
</div>
<label class="item item-input">
<span class="input-label">To 3</span>
<input type="text" value="">
</label>
<label class="item item-input">
<span class="input-label">From 1</span>
<input type="text" value="from input" id="from1">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 3</span>
<textarea id="textarea"></textarea>
</label>
<label class="item item-input">
<span class="input-label">To 1</span>
<input type="text" value="to input" id="to1">
</label>
<label class="item item-input">
<span class="input-label">From 4</span>
<input type="text" value="">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 1</span>
<textarea id="textarea" id="comment1">comment textarea</textarea>
</label>
<label class="item item-input">
<span class="input-label">To 4</span>
<input type="text" value="">
</label>
<label class="item item-input">
<span class="input-label">From 2</span>
<input type="text" value="" id="from2">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 4</span>
<textarea id="textarea"></textarea>
</label>
<label class="item item-input">
<span class="input-label">To 2</span>
<input type="text" value="" id="to2">
</label>
<label class="item item-input">
<span class="input-label">From 5</span>
<input type="text" value="">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 2</span>
<textarea id="textarea" id="comment2"></textarea>
</label>
<label class="item item-input">
<span class="input-label">To 5</span>
<input type="text" value="">
</label>
<label class="item item-input">
<span class="input-label">From 3</span>
<input type="text" value="">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 5</span>
<textarea id="textarea"></textarea>
</label>
<label class="item item-input">
<span class="input-label">To 3</span>
<input type="text" value="">
</label>
<button type="button" class="button button-block button-energized" ng-click="openModal()">
Open Modal
</button>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 3</span>
<textarea id="textarea"></textarea>
</label>
<button type="submit" class="button button-block button-calm">
Submit!
</button>
</div>
<label class="item item-input">
<span class="input-label">From 4</span>
<input type="text" value="">
</label>
</form>
<label class="item item-input">
<span class="input-label">To 4</span>
<input type="text" value="">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 4</span>
<textarea id="textarea"></textarea>
</label>
<label class="item item-input">
<span class="input-label">From 5</span>
<input type="text" value="">
</label>
<label class="item item-input">
<span class="input-label">To 5</span>
<input type="text" value="">
</label>
<label class="item item-input item-stacked-label">
<span class="input-label">Comment 5</span>
<textarea id="textarea"></textarea>
</label>
<button type="button" class="button button-block button-energized" ng-click="openModal()">
Open Modal
</button>
<button type="submit" class="button button-block button-calm">
Submit!
</button>
</div>
</form>
<p>
<a href="clickTests.html">Click Tests</a> -
<a href="tapInputs.html">Tap Inputs</a> -
<a href="/test/">CSS Tests</a>
</p>
</ion-content>
</ion-view>
</script>
<p>
<a href="clickTests.html">Click Tests</a> -
<a href="tapInputs.html">Tap Inputs</a> -
<a href="/test/">CSS Tests</a>
</p>
</ion-content>
</ion-view>
<script id="modal.html" type="text/ng-template">
<div class="modal" ng-controller="ModalCtrl">
@@ -251,6 +397,21 @@
angular.module('navTest', ['ionic'])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('input1', {
url: "/input1",
templateUrl: "input1.html"
})
.state('input2', {
url: "/input2",
templateUrl: "input2.html"
});
$urlRouterProvider.otherwise("/input1");
})
.controller('AppCtrl', function($scope, $ionicModal) {
$scope.openModal = function() {