Cómo diseñar diseños receptivos en Framer

Usar objetos de valor clave para hacer prototipos de dispositivos múltiples.

Si trabajas lo suficiente con los prototipos de Framer, eventualmente encontrarás el problema de cómo adaptar el diseño de un prototipo para manejar múltiples dispositivos y orientaciones. En lugar de crear un prototipo separado para cada situación, por ejemplo, uno para iPhone en orientación vertical y otro para iPad en horizontal, es posible diseñar un prototipo receptivo que adapte sus métricas según lo requiera la situación. Esto requiere cierta configuración, pero el proceso puede simplificarse enormemente mediante una estructura de datos conocida como objeto.

"Objeto" es un término vago que podría referirse a muchas cosas. Aquí, lo estamos usando para referirnos a una colección de pares clave-valor. Estos funcionan como variables: la clave le permite hacer referencia al par por un nombre, mientras que el valor contiene sus datos asociados.

En CoffeeScript, el lenguaje utilizado para hacer prototipos Framer, puede construir un objeto como:

objectName =
    valor clave
    anotherKey: anotherValue

(Tenga en cuenta que el signo igual sigue al nombre del objeto, pero se utilizan dos puntos para separar las claves y los valores).

Las jerarquías más avanzadas son posibles con objetos anidados, que es donde las cosas se ponen interesantes:

objectName =
    keySet1:
        valor clave
        anotherKey: anotherValue
    keySet2:
        valor clave
        anotherKey: anotherValue

Es fácil ver cómo esto puede traducirse en una solución para nuestro problema de diseño:

dimensionamiento =
    iphone:
        viewSidePadding: 20
    ipad:
        viewSidePadding: 40

Pero, ¿cómo accedemos a estos valores? Convenientemente, CoffeeScript proporciona dos métodos: notación de puntos y notación de corchetes. Para la notación de puntos, comenzamos con el nombre del objeto y luego caminamos por la jerarquía, separando las referencias con puntos:

print sizing.iphone.viewSidePadding

Con la notación entre paréntesis, envolvemos cada referencia entre paréntesis y comillas:

tamaño de impresión ["iphone"] ["viewSidePadding"]

(Tenga en cuenta que el nombre del objeto no está envuelto en nada).

Las comillas parecen una molestia al principio, pero de hecho son invaluables. Nos permiten construir los nombres de nuestras claves mediante expresiones. Podría, por ejemplo, hacer algo como esto:

tamaño de impresión ["iphone"] ["vista" + "SidePadding"]

Hasta ahora, esto no es más útil, pero puede comenzar a ver cómo estas referencias se pueden dividir y reconstruir según sea necesario.

También es posible mezclar y combinar estas anotaciones de la forma que desee:

tamaño de impresión ["iphone"]. viewSidePadding
print sizing.iphone ["viewSidePadding"]

Para que este enfoque de diseños receptivos funcione, necesitamos tres cosas:

  1. Un método para determinar el tipo de dispositivo.
  2. Un método para determinar la orientación del dispositivo.
  3. Un método para obtener el valor que coincide con estos.

En aras de la brevedad, aquí solo veremos el primer y el último elemento. (Uno de los prototipos adjuntos al final demostrará el paquete completo).

Cree un nuevo prototipo en Framer y agregue el siguiente código:

# especificaciones
dimensionamiento =
    viewTopPadding: 30
    iphone:
        viewSidePadding: 20
        itemMargin: 16
        itemSize: 250
    ipad:
        viewSidePadding: 40
        itemMargin: 64
        itemSize: 400

(Tenga en cuenta que algunos pares clave-valor viven directamente en el nivel superior. Estos son comunes tanto para iPhone como para iPad y sus valores no cambiarán con los dispositivos).

A continuación, agregue una función para detectar el tipo de dispositivo. La forma en que lo hagas dependerá de dónde quieras que se vea tu prototipo, pero aquí hay un método que funciona dentro de Framer:

# obtener tipo de dispositivo
checkDevice = (deviceType = "iphone") ->
    framerDevice = Framer.Device.deviceType
    deviceType = "iphone" if _.includes (framerDevice, "iphone")
    deviceType = "ipad" if _.includes (framerDevice, "ipad")
    dispositivo de retorno
Si su prototipo está destinado a la vista previa en dispositivos móviles, la detección de Screen.width puede ser un método más confiable.

Nuestra función checkDevice () devolverá la cadena “iphone” o “ipad”. Proporcionar la clave en un par clave-valor es todo lo que tenemos que agregar para obtener nuestra especificación numérica. Por ejemplo, esto ahora funcionará:

deviceType = checkDevice ()
value = "viewSidePadding"
tamaño de impresión [tipo de dispositivo] [valor]

Podemos expandir esto a una función de uso general que acepte un nombre de clave y devuelva el valor apropiado para el dispositivo actual. Puede usar el siguiente código, pero tenga en cuenta dos cosas al respecto:

  • Los valores más profundos en la jerarquía de objetos anularán a los que están más arriba. Si define un valor de especificación multiplataforma, es mejor no repetir ese valor a nivel de dispositivo.
  • Si no se encuentran valores coincidentes, la función imprime un mensaje de error.
# comprobar especificación
getSpec = (spec) ->
    if! spec entonces imprime "Necesito especificar un nombre de especificación".

    deviceType = checkDevice ()
    búsqueda = _.assign ({}, dimensionamiento, dimensionamiento [tipo de dispositivo])
    resultado = _.get (búsqueda, especificación)

    if! result entonces imprima "Valor no encontrado para la especificación llamada # {spec} en # {deviceType}".

    resultado devuelto

Con estas funciones en su lugar, simplemente necesitamos llamar a getSpec ("ourKeyName") donde "ourKeyName" es el nombre clave de un valor que queremos. Por lo tanto, getSpec ("viewSidePadding") devolverá 20 en iPhone pero 40 en iPad. getSpec ("viewTopPadding") devolverá 30 de cualquier manera.

Podemos eliminar rápidamente un carrusel de elementos basado en PageComponent utilizando nuestras especificaciones y sustituyendo llamadas a funciones para cualquiera de las dimensiones:

carrusel = nuevo componente de página
    ancho: ancho de pantalla
    x: getSpec ("viewSidePadding")
    y: getSpec ("viewTopPadding")
    height: getSpec ("itemSize")
    ancho: getSpec ("itemSize")
    clip: falso
    scrollVertical: falso
para i en [0..4]
    carouselItem = nueva capa
        padre: carrusel.contenido
        ancho: getSpec ("itemSize")
        height: getSpec ("itemSize")
        x: i * (getSpec ("itemSize") + getSpec ("itemMargin"))

Esto es suficiente para crear diseños que respondan a los cambios en el tipo de dispositivo. Si también desea adaptarse a la orientación, deberá detectar la orientación y volver a dibujar todas las capas cada vez que cambie. La forma más sencilla de lograr esto es envolver toda la creación de capas en una función de diseño. Cualquier cambio de orientación primero debe destruir todas las capas y luego llamar a la función de diseño para reconstruirlas, o la función de diseño puede manejar la destrucción de la capa como primer paso.

Si las capas existentes no se destruyen en el interruptor de orientación, terminará con pilas de capas duplicadas cuando se llama repetidamente a su función de diseño.

Envolver nuestra creación de carrusel en una función de diseño podría verse así:

# la función de diseño de vista
doLayout = () ->
    # destruir todas las capas, para evitar duplicaciones
    para la capa en Framer.CurrentContext.layers
        layer.destroy ()
    
    # crear un carrusel
    carrusel = nuevo componente de página
        ancho: ancho de pantalla
        x: getSpec ("viewSidePadding")
        y: getSpec ("viewTopPadding")
        height: getSpec ("itemSize")
        ancho: getSpec ("itemSize")
        clip: falso
        scrollVertical: falso
    
    # poblar el carrusel con celdas
    para i en [0..4]
        carouselItem = nueva capa
            padre: carrusel.contenido
            ancho: getSpec ("itemSize")
            height: getSpec ("itemSize")
            x: i * (getSpec ("itemSize") + getSpec ("itemMargin"))
# initialize
doLayout ()

Para experimentar con los prototipos y ver cómo estos mecanismos funcionan juntos, descargue el prototipo más simple y descargue uno con soporte de interruptor de orientación.

Otro enfoque es almacenar las especificaciones de tamaño específicas de iPad en un objeto de anulación separado. Descargue el prototipo de anulación para ver ese método en acción.

Para obtener más información sobre el diseño y el desarrollo, suscríbase a BPXL Craft y siga a Black Pixel en Twitter.

Black Pixel es una agencia creativa de productos digitales. Obtenga más información en blackpixel.com.