2010-04-01 10 views
91

Cuando inicio mi aplicación en modo retrato, funciona bien. Luego giro en el paisaje y se amplía. Para que se escale correctamente para el modo paisaje, tengo que tocar dos veces dos veces, primero para acercarme por completo (el comportamiento normal de doble toque) y nuevamente para alejar todo (otra vez, el comportamiento normal de doble toque) . Cuando se aleja, se aleja a la escala NUEVA correcta para el modo horizontal.¿Cómo restablezco la escala/el zoom de una aplicación web en un cambio de orientación en el iPhone?

Al volver a usar el retrato parece funcionar de forma más consistente; es decir, maneja el zoom para que la escala sea correcta cuando la orientación cambia de nuevo a retrato.

Estoy tratando de averiguar si esto es un error? o si esto es algo que se puede arreglar con JavaScript?

Con el meta contenido de la ventana gráfica, estoy configurando la escala inicial en 1.0 y NO estoy configurando la escala mínima o máxima (ni quiero hacerlo). Estoy configurando el ancho para el ancho del dispositivo.

¿Alguna idea? Sé que mucha gente estaría agradecida de tener una solución, ya que parece ser un problema persistente.

+1

Una solución perfecta: ¡No hay javascript! http://stackoverflow.com/a/8727440/805787 – Steeven

Respuesta

85

Jeremy Keith() tiene una buena solución para esto en su blog Orientation and scale

Mantenga el marcado escalable al no establecer una escala máxima en el marcado.

<meta name="viewport" content="width=device-width, initial-scale=1"> 

A continuación, desactivar la escalabilidad con javascript carga hasta gesturestart cuando se permite la escalabilidad de nuevo con este script:

if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i)) { 
    var viewportmeta = document.querySelector('meta[name="viewport"]'); 
    if (viewportmeta) { 
     viewportmeta.content = 'width=device-width, minimum-scale=1.0, maximum-scale=1.0, initial-scale=1.0'; 
     document.body.addEventListener('gesturestart', function() { 
      viewportmeta.content = 'width=device-width, minimum-scale=0.25, maximum-scale=1.6'; 
     }, false); 
    } 
} 

Actualización 22-12-2014:
En una iPad 1, esto no funciona, falla en eventlistener. He descubierto que la eliminación de .body correcciones que:

document.addEventListener('gesturestart', function() { /* */ }); 
+4

¿Seguro que esto es mejor que deshabilitar el zoom?La mejor solución que he encontrado todavía :) – danwellman

+0

esto funcionó para mí también. ¡Gracias! – 29er

+0

Hmm, esto todavía desactiva la capacidad de acercar. ¿Alguien tiene una solución simple que no hace esto? –

1

MobileSafari admite el evento orientationchange en el objeto window. Lamentablemente, no parece haber una manera de controlar directamente el zoom a través de JavaScript. Quizás podrías escribir/cambiar dinámicamente la etiqueta meta que controla la ventana gráfica, pero dudo que eso funcione, solo afecta el estado inicial de la página. Tal vez podrías usar este evento para cambiar el tamaño de tu contenido usando CSS. ¡Buena suerte!

+3

¡Gracias! Sí, traté de cambiar dinámicamente los valores de la ventana de metaetiqueta y no hizo nada. Me parece que si gira en Horizontal, quiere que se amplíe correctamente para mantener la escala de modo que la página encaje en la ventana de Safari. ¡Me parece muy extraño que este no sea el comportamiento predeterminado! – Elisabeth

14

Tuve el mismo problema, y ​​establecer la escala máxima = 1.0 me funcionó.

Editar: Como se mencionó en los comentarios, esto deshabilita el zoom del usuario excepto cuando el contenido excede la resolución de ancho. Como se mencionó, esto podría no ser sabio. También podría ser deseado en algunos casos.

El código de visualización:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0;"> 
+0

¡Gracias, intentaré esto! – Elisabeth

+0

Buena solución. Hace un buen trabajo manteniendo la página en un nivel de zoom constante (en relación con el ancho del dispositivo) a través de cambios de orientación. ¡Gracias por compartirlo! –

+17

¡El inconveniente es que los usuarios con discapacidad no pueden hacer zoom en su sitio! –

3

Si tiene el ancho establecido en el visor:

<meta name = "viewport" content = "width=device-width; initial-scale=1.0; 
maximum-scale=1.0;" /> 

Y a continuación, cambiar la orientación que se acercará al azar en ocasiones (sobre todo si se está arrastrando en la pantalla) para arreglar esto no establezca un ancho aquí Yo utilicé:

<meta id="viewport" name="viewport" content="initial-scale=1.0; user-scalable=0; 
minimum-scale=1.0; maximum-scale=1.0" /> 

Esto corrige el Acerque todo lo que pase, puede usar el evento window.onorientationchange o si desea que sea independiente de la plataforma (útil para probar) el método window.innerWidth.

0

Elisabeth puede cambiar el contenido de la ventana gráfica dinámica mediante la adición de la propiedad "id" a la metaetiqueta:

<meta name="viewport" id="view" content="user-scalable=yes, width=device-width minimum-scale=1, maximum-scale=1" /> 

continuación, sólo puede llamar por javascript:

document.getElementById("view").setAttribute('content','user-scalable=yes, width=device-width, minimum-scale=1, maximum-scale=10'); 
+0

@bridgestew si quiere cambiar el zoom o la ventana gráfica use dinámicamente la subvista vista de desplazamiento contenida en uiwebview. se agregó un snipet de muestra en otro hilo: [link] (http://stackoverflow.com/questions/2890673/iphone-uiwebview-width-does-not-fit -after-zooming-operation-uiinterfaceorientat/5015129 # 5015129) –

+4

@Elisabeth ¿funciona para usted? No restablece el zoom cuando me cambio en el modo horizontal. –

+1

No, tampoco funciona para mí. – Elisabeth

18

Scott Jehl se le ocurrió una solución fantástica que utiliza el acelerómetro para anticipar los cambios de orientación. Esta solución es muy sensible y no interfiere con los gestos de zoom.

https://github.com/scottjehl/iOS-Orientationchange-Fix

Cómo funciona: Esta corrección obras de escuchar el acelerómetro del dispositivo para predecir cuándo un cambio de orientación está a punto de ocurrir. Cuando considere que una orientación cambia inminente, la secuencia de comandos desactiva el zoom del usuario , permitiendo que el cambio de orientación ocurra correctamente, con el zoom desactivado. La secuencia de comandos restaura el zoom una vez que el dispositivo está orientado cerca de la posición vertical, o después de haber cambiado su orientación . De esta forma, el zoom del usuario nunca se deshabilita mientras la página está en uso .

fuente minified:

/*! A fix for the iOS orientationchange zoom bug. Script by @scottjehl, rebound by @wilto.MIT License.*/(function(m){if(!(/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1)){return}var l=m.document;if(!l.querySelector){return}var n=l.querySelector("meta[name=viewport]"),a=n&&n.getAttribute("content"),k=a+",maximum-scale=1",d=a+",maximum-scale=10",g=true,j,i,h,c;if(!n){return}function f(){n.setAttribute("content",d);g=true}function b(){n.setAttribute("content",k);g=false}function e(o){c=o.accelerationIncludingGravity;j=Math.abs(c.x);i=Math.abs(c.y);h=Math.abs(c.z);if(!m.orientation&&(j>7||((h>6&&i<8||h<8&&i>6)&&j>5))){if(g){b()}}else{if(!g){f()}}}m.addEventListener("orientationchange",f,false);m.addEventListener("devicemotion",e,false)})(this); 
+0

¡Agradable! Parece una solución elegante. – Elisabeth

+1

¡esta debería ser la respuesta aceptada! Desearía haber visto esto primero antes de perder una hora en las soluciones anteriores :) – tmsimont

+1

después de probar esto es una solución poco confiable :(es inconsistente, y después de leer el código puedo ver por qué ... el "umbral" de movimiento definido no siempre se alcanza, especialmente si mantiene el ipad en un ángulo mientras gira – tmsimont

0

He encontrado una nueva solución, diferente de cualquier otro que he visto, desactivando el zoom iOS nativa, y en lugar de implementar la funcionalidad de zoom en JavaScript.

Una excelente experiencia en las otras soluciones al problema del zoom/orientación es por Sérgio Lopes: A fix to the famous iOS zoom bug on orientation change to portrait.

<!DOCTYPE html> 
<html> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
    <meta name="viewport" id="viewport" content="user-scalable=no,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0" /> 
    <title>Robocat mobile Safari zoom fix</title> 
    <style> 
     body { 
      padding: 0; 
      margin: 0; 
     } 
     #container { 
      -webkit-transform-origin: 0px 0px; 
      -webkit-transform: scale3d(1,1,1); 
      /* shrink-to-fit needed so can measure width of container http://stackoverflow.com/questions/450903/make-css-div-width-equal-to-contents */ 
      display: inline-block; 
      *display: inline; 
      *zoom: 1; 
     } 
     #zoomfix { 
      opacity: 0; 
      position: absolute; 
      z-index: -1; 
      top: 0; 
      left: 0; 
     } 
    </style> 
</head> 

<body> 
    <input id="zoomfix" disabled="1" tabIndex="-1"> 
    <div id="container"> 
     <style> 
      table { 
       counter-reset: row cell; 
       background-image: url(http://upload.wikimedia.org/wikipedia/commons/3/38/JPEG_example_JPG_RIP_010.jpg); 
      } 
      tr { 
       counter-increment: row; 
      } 
      td:before { 
       counter-increment: cell; 
       color: white; 
       font-weight: bold; 
       content: "row" counter(row) ".cell" counter(cell); 
      } 
     </style> 
     <table cellspacing="10"> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
      <tr><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td><td> 
     </table> 
    </div> 

    <script> 
    (function() { 
     var viewportScale = 1; 
     var container = document.getElementById('container'); 
     var scale, originX, originY, relativeOriginX, relativeOriginY, windowW, windowH, containerW, containerH, resizeTimer, activeElement; 
     document.addEventListener('gesturestart', function(event) { 
      scale = null; 
      originX = event.pageX; 
      originY = event.pageY; 
      relativeOriginX = (originX - window.pageXOffset)/window.innerWidth; 
      relativeOriginY = (originY - window.pageYOffset)/window.innerHeight; 
      windowW = window.innerWidth; 
      windowH = window.innerHeight; 
      containerW = container.offsetWidth; 
      containerH = container.offsetHeight; 
     }); 
     document.addEventListener('gesturechange', function(event) { 
      event.preventDefault(); 
      if (originX && originY && event.scale && event.pageX && event.pageY) { 
       scale = event.scale; 
       var newWindowW = windowW/scale; 
       if (newWindowW > containerW) { 
        scale = windowW/containerW; 
       } 
       var newWindowH = windowH/scale; 
       if (newWindowH > containerH) { 
        scale = windowH/containerH; 
       } 
       if (viewportScale * scale < 0.1) { 
        scale = 0.1/viewportScale; 
       } 
       if (viewportScale * scale > 10) { 
        scale = 10/viewportScale; 
       } 
       container.style.WebkitTransformOrigin = originX + 'px ' + originY + 'px'; 
       container.style.WebkitTransform = 'scale3d(' + scale + ',' + scale + ',1)'; 
      } 
     }); 
     document.addEventListener('gestureend', function() { 
      if (scale && (scale < 0.95 || scale > 1.05)) { 
       viewportScale *= scale; 
       scale = null; 
       container.style.WebkitTransform = ''; 
       container.style.WebkitTransformOrigin = ''; 
       document.getElementById('viewport').setAttribute('content', 'user-scalable=no,initial-scale=' + viewportScale + ',minimum-scale=' + viewportScale + ',maximum-scale=' + viewportScale); 
       document.body.style.WebkitTransform = 'scale3d(1,1,1)'; 
       // Without zoomfix focus, after changing orientation and zoom a few times, the iOS viewport scale functionality sometimes locks up (and completely stops working). 
       // The reason I thought this hack would work is because showing the keyboard is the only way to affect the viewport sizing, which forces the viewport to resize (even though the keyboard doesn't actually get time to open!). 
       // Also discovered another amazing side effect: if you have no meta viewport element, and focus()/blur() in gestureend, zoom is disabled!! Wow! 
       var zoomfix = document.getElementById('zoomfix'); 
       zoomfix.disabled = false; 
       zoomfix.focus(); 
       zoomfix.blur(); 
       setTimeout(function() { 
        zoomfix.disabled = true; 
        window.scrollTo(originX - relativeOriginX * window.innerWidth, originY - relativeOriginY * window.innerHeight); 
        // This forces a repaint. repaint *intermittently* fails to redraw correctly, and this fixes the problem. 
        document.body.style.WebkitTransform = ''; 
       }, 0); 
      } 
     }); 
    })(); 
    </script> 
</body> 
</html> 

Se podría mejorar, pero para mis necesidades que evita los principales inconvenientes que se producen con todas las otras soluciones que he visto. Hasta ahora solo lo he probado usando Safari móvil en un iPad 2 con iOS4.

El foco()/desenfoque() es una solución para evitar el bloqueo ocasional de la funcionalidad de zoom que puede ocurrir después de cambiar la orientación y el zoom varias veces.

Al configurar document.body.style se fuerza un repintado a pantalla completa, lo que evita ocasionalmente problemas intermitentes en los que el repintado falla gravemente después del zoom.

1

He estado usando esta función en mi proyecto.

function changeViewPort(key, val) { 
    var reg = new RegExp(key, "i"), oldval = document.querySelector('meta[name="viewport"]').content; 
    var newval = reg.test(oldval) ? oldval.split(/,\s*/).map(function(v){ return reg.test(v) ? key+"="+val : v; }).join(", ") : oldval+= ", "+key+"="+val ; 
    document.querySelector('meta[name="viewport"]').content = newval; 
} 

por lo que sólo addEventListener:

if(/iPad|iPhone|iPod|Android/i.test(navigator.userAgent)){ 
    window.addEventListener("orientationchange", function() { 
     changeViewPort("maximum-scale", 1); 
     changeViewPort("maximum-scale", 10); 
    } 
} 
0

Ésta es otra manera de hacerlo, que parece funcionar bien.

  1. Establecer la etiqueta meta para restringir la ventana gráfica a escala = 1, lo que impide una función de zoom:

    < meta name = "viewport" content = "width = dispositivo de ancho, inicial escala = 1, mínimo escala = 1, de máxima escala = 1 ">

  2. con Javascript, cambie la etiqueta meta medio segundo más tarde para permitir zoom:

    setTimeout (function() {document.querySelector (" meta [nombre = ventana] "). setAttribute ('contenido', ' width = device-width, initial-scale = 1 ');}, 500);

  3. De nuevo con javascript, sobre el cambio de orientación, vuelva a cargar la página:

    window.onorientationchange = function() {window.location.reload();};

Cada vez que reorienta el dispositivo, la página se vuelve a cargar, inicialmente sin zoom. Pero 1/2 segundo después, se restaura la capacidad de zoom.

+4

Responder a una pregunta 5 años después de que se le preguntó es algo ... Lamentablemente, así no funciona la web en 2015. NO recarga la página cuando el el usuario gira su dispositivo. – Pierre

0

Encontré una solución implementada muy fácilmente. Establezca el foco en un elemento de texto que tenga un tamaño de fuente de 50 px al completar el formulario. No parece funcionar si el elemento de texto está oculto, pero ocultar este elemento se realiza fácilmente al establecer las propiedades de color de los elementos para que no tengan opacidad.

Cuestiones relacionadas