Para mis necesidades, me pareció más fácil de usar una cabecera posicionado absoluto, lo oculta antes de desplazamiento y demostrar que cuando rollo acabado (necesito el mismo código para apoyar iOS4 y Android).
Para mis propósitos, que ocultan la cabecera de un evento touchstart
, y muestran de nuevo en touchend
o scroll
evento (además de algunos temporizadores para mejorar la capacidad de respuesta/reducir el parpadeo). Destella, pero es el mejor compromiso que pude encontrar. Uno puede detectar el inicio del desplazamiento utilizando el touchmove
evento (jQuery hace esto), pero encontré touchmove
no funcionó así para mí porque:
regularmente el iPad deja de hacer un repintado antes de desplazarse (es decir, el encabezado absoluto permanece atascado, aunque se modificó el top
antes de que se inicie el desplazamiento).
cuando un elemento de entrada se enfoca, el iPad centra automáticamente el elemento, pero el evento scrollstart no se dispara (porque no hay movimiento si solo click
es una entrada).
La implementación de una cabecera fija en iOS5 podría mejorarse mediante el uso de un enfoque híbrido de posicionamiento fijo y absoluto:
posicionamiento fijo utilizado para iOS5 hasta una entrada obtiene foco.
cuando una entrada obtiene el foco (mostrando el teclado), cambie al código de posicionamiento absoluto iOS4.
cuando el teclado está cerrado, cambie de nuevo a la posición fija.
Código para detectar cuando el teclado está cerrado (por ejemplo, utilizando guardallaves teclado) es registrar el evento DOMFocusOut
en el elemento document
y hacer algo como el siguiente código. El tiempo de espera es necesario porque el evento DOMFocusOut
puede activarse cuando un elemento obtiene el foco y otro lo pierde.
function document_DOMFocusOut() {
clearTimeout(touchBlurTimer);
touchBlurTimer = setTimeout(function() {
if (document.activeElement == document.body) {
handleKeyboardHide();
}
}.bind(this), 400);
}
Mi código de cabecera fijo es algo así como:
{
setup: function() {
observe(window, 'scroll', this, 'onWinScroll');
observe(document, 'touchstart', this, 'onTouchStart');
observe(document, 'touchend', this, 'onTouchEnd');
if (isMobile) {
observe(document, 'DOMFocusOut', this, 'docBlurTouch');
} else if (isIE) {
// see http://ajaxian.com/archives/fixing-loss-of-focus-on-ie for code to go into this.docBlurIe()
observe(document, 'focusout', this, 'docBlurIe');
} else {
observe(isFirefox ? document : window, 'blur', this, 'docBlur');
}
},
onWinScroll: function() {
clearTimeout(this.scrollTimer);
this.scrolling = false;
this.rehomeAll();
},
rehomeAll: function() {
if ((isIOS5 && this.scrolling) || isIOS4 || isAndroid) {
this.useAbsolutePositioning();
} else {
this.useFixedPositioning();
}
},
// Important side effect that this event registered on document on iOs. Without it event.touches.length is incorrect for any elements in the document using the touchstart event!!!
onTouchStart: function(event) {
clearTimeout(this.scrollTimer);
if (!this.scrolling && event.touches.length == 1) {
this.scrolling = true;
this.touchStartTime = inputOrOtherKeyboardShowingElement(event.target) ? 0 : (new Date).getTime();
// Needs to be in touchStart so happens before iPad automatic scrolling to input, also not reliable using touchMove (although jQuery touch uses touchMove to unreliably detect scrolling).
this.rehomeAll();
}
},
onTouchEnd: function(event) {
clearTimeout(this.scrollTimer);
if (this.scrolling && !event.touches.length) {
var touchedDuration = (new Date).getTime() - this.touchStartTime;
// Need delay so iPad can scroll to the input before we reshow the header.
var showQuick = this.touchStartTime && touchedDuration < 400;
this.scrollTimer = setTimeout(function() {
if (this.scrolling) {
this.scrolling = false;
this.rehomeAll();
}
}.bind(this), showQuick ? 0 : 400);
}
},
// ... more code
}
jQuery móvil es compatible con scrollstart y scrollstop eventos:
var supportTouch = $.support.touch,
scrollEvent = "touchmove scroll",
touchStartEvent = supportTouch ? "touchstart" : "mousedown",
touchStopEvent = supportTouch ? "touchend" : "mouseup",
touchMoveEvent = supportTouch ? "touchmove" : "mousemove";
function triggerCustomEvent(obj, eventType, event) {
var originalType = event.type;
event.type = eventType;
$.event.handle.call(obj, event);
event.type = originalType;
}
// also handles scrollstop
$.event.special.scrollstart = {
enabled: true,
setup: function() {
var thisObject = this,
$this = $(thisObject),
scrolling,
timer;
function trigger(event, state) {
scrolling = state;
triggerCustomEvent(thisObject, scrolling ? "scrollstart" : "scrollstop", event);
}
// iPhone triggers scroll after a small delay; use touchmove instead
$this.bind(scrollEvent, function(event) {
if (!$.event.special.scrollstart.enabled) {
return;
}
if (!scrolling) {
trigger(event, true);
}
clearTimeout(timer);
timer = setTimeout(function() {
trigger(event, false);
}, 50);
});
}
};
resulta que esto es un error de IOS, que se irá este problema por ahora, pero sus sugerencias son válidas, así que marcaré esta respuesta correcta – jas
jas, ¿es posible dar el enlace para la url de problema de error de iOS? – robocat
No he visto lo que se ha solucionado en iOS6, pero se ha agregado al menos un error adicional: http://igstudio.blogspot.com/2012/09/positionfixed-in-ios-6.html (también sospecha que al darle al div fijo una propiedad de CSS que lo fuerza a tener una composición acelerada por hardware también podría arreglarlo). – robocat