lunes, 6 de octubre de 2014

HTML Orientación Horizontal

Hola de nuevo, desde hace unas semanas estoy creando a ratos como “Home Project” una aplicación crossplatform orientada a cloud y mobile con HTML y javascript. Os planteo un temilla que me encuentro con HTML a la hora de publicar en Windows 8.1.

La aplicación de momento funciona en Android y Windows 8.1 (Store). Consigo ejecutarla como aplicación en ambos entornos (usando cordova / phonegap) pero queda un poco rara comparada con el resto de aplicaciones de la Store de Windows. Con cordova / phonegap hay modos de hacer que se cargue una hoja de estilos u otra en función de la plataforma y ya lo hago para dotar de un estilo más “metro” o más “Android” los mismos ítems pero opino que con esto no es suficiente.

Por defecto un documento HTML crece a largo, es decir, en vertical. A medida que añadimos contenido se van incluyendo filas que generalmente aprovechan el ancho de la pantalla. Es raro encontrarnos scroll horizontal en una página HTML y muy habitual encontrarnos scroll vertical.

Imaginaros que nos interesa que nuestro documento web siempre se ajuste al espacio vertical de la pantalla y crezca a lo ancho (como Falete). No me refiero a leer inclinando 90º la cabeza, la orientación del contenido seguiría siendo la misma. Me refiero a que si tenemos una lista dinámica en vez de ir ubicando los ítems uno debajo de otro los colocásemos uno al lado de otro y el documento se dimensionase horizontalmente según el contenido de la lista.

areaTIC: Html Orientación Horizontal

Esto podría serte útil para aplicaciones de la Windows Store si no usas WinJS y quieres desarrollar una app en HTML. Si tienes un Windows 8 y juegas un poco con alguna aplicación de la Store típica o con las que ya vienen con el sistema operativo, verás que la orientación es horizontal. Ya que estamos, estaría bien que el aplicativo que estamos desarrollando sea capaz de adaptarse fácilmente a un modelo u otro para no tener que hacer un desarrollo específico para cada plataforma ni hacer el mismo layout para todas.

Veamos como he planteado el tema en mi proyectillo:

Listas en horizontal


Imagina una lista de elementos dinámica, seguramente conozcas Bootstrap y sabrás que jugando con la clase col-* en los elementos html de la lista puedes definir fácilmente si quieres 2 columnas por fila o 3 o 4 pero en todo caso siempre se ajustará al ancho por defecto de la pantalla cuando lo superas pasas a nueva fila.

Para conseguir que el ancho del documento crezca a medida que se vayan mostrando ítems tendrás que hacer algo más. Os paso un link donde propone algunos trucos, en mi caso sigo el consejo del autor del artículo y opto por usar un table para mostrar las listas.

Si sustituyes los divs por la estructura de table, tr, td y haces que cada elemento de la lista sea un td nuevo ya lo tienes. Al mostrar los elementos se redimensiona la lista y esto provoca que haya scroll horizontal y hasta aquí bien. El siguiente problema es que el header, footer y resto de contenido de la página para que quede bien se debería ajustar al nuevo ancho de la lista… Dicho de otro modo ha crecido el elemento table pero no el documento html donde está contenida la tabla. Para solucionarlo sería ideal saber cuando ha acabado de mostrar elementos la lista dinámica, obtener el ancho de la tabla y forzar la redimensión del contenedor. Os explico cómo lo he hecho.

Mi aplicación parte de una base desarrollada en Angular que me permite dotar de cierta estructura al código y mil ventajas más que no es el momento de hablar. Para mostrar una lista de elementos dinámica se suele usar ng-repeat. ¿Cómo podría saber cuándo acaba de mostrar la lista? Bien, nos creamos una directiva personalizada y hacemos referencia en el mismo tag donde tengo ng-repeat.

Directiva:
layoutModule.directive('onFinishRender', function ($timeout) {
        return {
            restrict: 'A',
            link: function (scope, element, attr) {
                if (scope.$last === true) {
                    $timeout(function () {
                        scope.$emit('ngRepeatFinished');
                    });
                }
            }
        }
    });
Elemento lista:
<td ng-repeat="photo in photos | filter:query | orderBy:orderProp" ng-class="cssListType()" on-finish-render>
Controlador de la vista donde está ubicada la lista (o jerárquicamente superior, depende como hayas estructurado la aplicación te evitarás tener que crearlo en todos los controladores que tengan listas):
$scope.$on('ngRepeatFinished', function (ngRepeatFinishedEvent) {
            container.style.width = list.clientWidth + 100 + 'px';            
        });
Vale, ahora lo malo es que si siempre uso td para las listas siempre serán horizontales y me gustaría hacerlo variable como comentaba… Yo lo que he hecho es crearme una constante en mi Angular Module correspondiente y una directiva para mostrar el elemento de la lista (td o div) en función del valor de esta constante… por tanto si quiero publicar para Windows cambio la constante y publico, la vuelvo a cambiar y publico para Android.

Rueda del mouse


En mi caso para Windows lo estoy probando directamente instalando en mi máquina el ejecutable ya que es un Windows 8.1 y echo en falta que reaccione al evento de mover la rueda del ratón ya que las aplicaciones originales de la Store lo hacen...

Navegando llegué a este plug-in, se trata de descargarlo y hacer referencia en la página contenedora de la aplicación.

El segundo paso es incluir este script en la página contenedora de la aplicación (puede ser que lo tengas que ajustar en función de cómo estructures el contenido):
      <script>
            $(function () {
                $(window).mousewheel(function(event, delta) {
                    event.preventDefault();
                    var scroll = $("body").scrollLeft();
                    $("body").scrollLeft(scroll - (delta * 20));
                });
            });
        </script>
El siguiente paso sería aprovechar la constante que hemos creado en Angular para determinar que tipo de lista debería usar la directiva... esta misma constante podríamos usarla para hacer que la rueda se comporte como habitualmente o en horizontal según la plataforma y tamaño de la pantalla cliente.

Hasta aquí el artículo de hoy, no te cortes a opinar, proponer alternativas o dudas vía comentarios, mail o redes sociales! Recuerda echar un vistazo al archivo de areaTIC, tal vez encuentres algún artículo que pueda interesarte. Hasta la próxima!