Home » Guías » 3D Touch, guía de implementación en iOS 9
3DTouch

3D Touch, guía de implementación en iOS 9

Esta guía está certificada con el uso de Swift 2.1, Xcode 7.1 e iOS 9.1

3D Touch, la funcionalidad estrella de los nuevos modelos iPhone 6s y 6s Plus. Una función tan simple como la detección por parte del terminal del nivel de presión que ejercemos en la pantalla. La forma en que está implementado es a partir de unos pequeños electrodos en los bordes de la pantalla, con sensores analógicos, que tienen la capacidad de distinguir entre un toque o una presión, siendo capaces incluso de distinguir esta en diferentes niveles de mayor o menor presión.

3D Touch iPhone

Una vez el terminal detecta una presión en una zona de la pantalla, el taptic engine genera una vibración de respuesta a nuestra presión, además de provocar la respuesta inmediata dentro del sistema: el gesto que genera un evento que, si es dentro de nuestra app, podemos detectar y hacer que nuestra app tenga una respuesta al mismo. Siempre siendo coherentes con las guías de interfaz humana de Apple a la hora de hacer que nuestra app reaccione.

La forma de implementar esta función en nuestras apps depende de nosotros mismos, pensando o buscando dónde podemos integrar las funcionalidades asociadas y, como hemos dicho, siguiendo las directrices de Apple. Las posibles funciones o gestos que tenemos son: peek, pop y acciones rápidas.

Pero cualquiera de ellas podrá ser realizada, siempre y cuando nuestro terminal soporte estas. Para ello, primero hemos de realizar una comprobación de un parámetro del sistema, en la clase que herede del controlador de vista donde queremos implementar este gesto.

Hecho esto, obtendremos un error porque para poder utilizar registerForPreviewingWithDelegate, self (nuestra clase) ha de conformarse al protocolo UIViewControllerPreviewingDelegate y para ello hemos de implementar las dos funciones que son requeridas por este, ambas polimorfismos de previewingContext.

Así que, como podemos ver, la forma de implementar el 3D Touch pasa por usar el patrón de delegaciones dentro de nuestra clase, método obvio ya que cuando pulsemos en la pantalla se lanzarán los métodos o funciones pertinentes. En el caso que estamos usando de ejemplo, nuestra clase en Swift quedaría algo así:

Ya tenemos la clase preparada para implementar los gestos de 3D Touch, los cuales si no soporta nuestro terminal no harán nada y listo porque no se ejecutará la instrucción registerForPreviewingWithDelegate que inicializa la delegación con la vista de nuestro controlador. Y antes que lo pregunten: no, no se puede probar en el simulador, solo podrán verificar esta función en un dispositivo real.

Peek

Peek, primera presión

El gesto peek, es lo que Apple define como la primera interacción a la presión. Cuando pulsamos una zona de la pantalla determinada y ejercemos una leve presión, esto genera el gesto peek que nos permite realizar una previsualización del elemento que hemos pulsado. Por ejemplo, si estamos en el email y hacemos peek, se nos mostrará una ventana emergente con el correo para que podamos leerlo. Si estamos en Instagram y hacemos peek sobre una foto del mosaico, la veremos en grande mientras mantengamos la presión. Cuando soltemos esta desaparecerá.

No obstante, el flujo no varía de la app convencional. Es decir, no tenemos que crear una nueva vista dentro de nuestro flujo para que sea usada en el gesto de peek. Lo que realmente hacemos es usar la misma vista detalle que ya tendríamos normalmente, pero como fuente de previsualización. Por verlo más claro, normalmente en nuestro storyboard tendremos la vista con el total de elementos que queremos mostrar (como por ejemplo, una vista de colecciones UICollectionViewController) y al pulsar lo que haremos será invocar la misma vista detalle que usaríamos al pulsar normalmente en el elemento. La diferencia es que en vez de usar un segue de navegación que cambia una vista por otra, usamos un preview asociado a la pulsación.

En este caso, lo más cómodo es recuperar del storyboard asociado el controlador de la vista que usemos como detalle para poder precargar las condiciones de la previsualización. En nuestro caso vistaDetalle es como se llama tanto el UIViewController como la clase asociada al mismo.

Estamos recuperando el UIViewController que vamos a mostrar dentro de nuestro storyboard, y eso además nos permite configurarlo, pues la clase vistaDetalle corresponde a un ámbito class donde podremos decir qué propiedades o métodos son necesarios para que esta se preconfigure correctamente antes de ser mostrada con el gesto peek.

Por ejemplo, si hemos pulsado una foto, tendremos que asegurarnos que nuestra vista mostrará esa foto (y no otra) cuando hagamos el gesto. Y para ello usamos ese espacio que hay entre el guard y el return que devuelve el viewController asociado al detalle que hemos recuperado.

Con esto ya tenemos hecho por completo el peek, aunque podemos ir más allá con esta implementación.

Acciones rápidas

Otra de las posibles implementaciones del 3D Touch son las acciones rápidas, las cuales tienen dos posibles contextos: fuera de nuestra app, como acceso directo a una parte concreta de la misma o dentro de la misma, como complemento de un peek en vez de hacer un pop.

Primero, para continuar con nuestro ejemplo, vamos a ver cómo sería con el uso dentro de un peek. Para ello, es algo tan simple como sobrescribir la función previewActionItems dentro de la clase asociada a nuestra vista detalle. En este caso, y siguiendo el ejemplo anterior, nos estamos refiriendo a la clase vistaDetalle. En ella, simplemente creamos objetos UIPreviewAction que tendrán unos parámetros de instanciación que les darán título y estilo (a partir de una enumeración) y luego un último parámetro de manejador (o handler) que será un closure con los parámetros de la acción que se ha ejecutado y la vista controlador asociada. En este closure será donde dictemos el código de lo que ha de hacerse cuando se seleccione esa acción rápida.

En el ejemplo, lo que hemos hecho es crear dos opciones que aparecerán al mover hacia arriba la ventana de previsualización mostrada por el peek. La tercera opción, la calificada como .Destructive aparecerá en rojo.

Acciones Rápidas Peek

De esta simple forma, aprovechamos para configurar las acciones rápidas asociadas al peek como gesto. El iPhone de la izquierda en la imagen superior mostraría los objetos UIPreviewAction en el orden que los hayamos puesto en el array. El iPhone de la derecha es un ejemplo implementado por el propio sistema dentro del email, para ilustrarnos mejor en las acciones rápidas dentro del gesto peek.

Y cuando haces pop…

Lo último que nos queda ver, del proceso peek, acción rápida y pop, es este último. El pop es lo que sucede cuando, dentro de un peek, hacemos una presión aun más fuerte y nos lleva al despliegue normal de la vista de detalle. Es decir, lo mismo que hubiera sucedido (o sucede) si pulsamos el elemento en la vista maestra de una manera normal y dejamos que el segue realice su normal cometido entre vistas dentro de un storyboard.

En este caso, la implementación es bien sencilla, ya que simplemente nos limitamos a mostrar el viewController que la propia función ha recibido como parámetro automáticamente.

Con esto, tendríamos cerrado todo el proceso. Lo que hemos de recordar aquí, es que la función que hemos puesto es la más básica, pero podríamos hacer cualquier proceso que nos permita preconfigurar la vista detalle e incluso hacer alguna animación.

Ahora, hecho a máquina

Peek y Pop

Toda esta implementación de peek y pop, la estamos haciendo manualmente, programando. De hecho, en Apple Coding es como nos gusta hacer las cosas pues el control que tenemos sobre las acciones es mejor (bajo nuestro punto de vista).

Pero también podríamos hacerla directamente si en el editor de interfaces de iOS. Para ello en el storyboard elegimos el segue que conecta la vista maestra con la detalle. Aquí podemos configurar también un comportamiento más automático de previsualización entre el maestro y el detalle y tenerlo implementado.

Peek & Pop Segue

Cuando pulsamos en él y nos vamos a sus propiedades, veremos que tenemos la opción de indicar de manera automática las asociaciones y crear estos gestos de una forma directa.

Pulsamos en el check que reza: Peek & Pop, Preview and Commit Segues. Si pulsamos ahí podremos, bien dejarlo de manera automática para que el preview (el peek) use el mismo segue que el commit (el del pop) y viceversa, lo cual nos resultará útil para un caso donde la asociación entre el maestro y el detalle sea directa porque lo que haga el segue será lo mismo que también haga el gesto peek y pop en cuanto a datos del detalle.

O podemos elegir la opción custom y especificar nosotros el identificador del segue que queramos usar para cada una de estas operaciones, incluyendo los parámetros que normalmente usaríamos de clase o módulo.

En caso de hacerlo de hacerlo de manera personalizada con custom, indicamos el identificador del segue. En ambos casos, siempre podemos sobrescribir la función prepareForSegue para capturar la llamada en la clase del maestro, dentro del gesto peek y actuar en consecuencia.

Como vemos, tenemos varias formas de implementarlo que se pueden adaptar a nuestras necesidades.

Acciones rápidas de inicio

Por último, nos quedan las acciones rápidas de inicio: aquellas que nos permiten tener accesos directos a partes concretas de nuestra app a través de opciones contextuales que se nos muestran al hacer peek sobre el icono de nuestra app. Lo importante aquí es distinguir entre acciones fijas y acciones dinámicas. Las primeras, van definidas a nivel de configuración de aplicación dentro del fichero info.plist.

Para implementarlo, solo hay que ir a este fichero, donde tenemos todo lo importante que configura nuestra app, ponernos en la última línea y pulsar la tecla Enter.

Una vez allí escribimos UIApplicationShortcutItems y luego elegimos, a su derecha, el tipo Array para este nodo que acabamos de crear. Pulsamos la flecha derecha para que se despliegue el array (veremos que la flecha a la izquierda pasa de señalar a la derecha a señalar hacia abajo) y luego creamos otro nodo pulsando Enter, que inmediatamente se denominará item0. Lo cambiamos a tipo Dictionary, de nuevo a la derecha y pulsamos Enter.

Una vez hecho esto, podemos crear nodos usando las siguientes claves:

  • UIApplicationShortcutItemType: Identificador de tipo cadena del tipo de acceso rápido que se propagará a la app y por el que podremos identificar qué opción rápida se pulsó al iniciarla. Es un dato obligatorio.
  • UIApplicationShortcutItemTitle: Título que tendrá el acceso directo, en letra más destacada. Este dato es obligatorio que se indique en todos los casos.
  • UIApplicationShortcutItemIconType: Crea un acceso con un icono predefinido del sistema. Tenemos bastantes opciones a utilizar, que corresponden con imágenes que ya están definidas para diferentes propósitos: Compose, Play, Pause, Add, Location, Search, Share, Prohibit, Contact, Home, MarkLocation, Favorite, Love, Cloud, Invitation, Confirmation, Mail, Message, Date, Time, CapturePhoto, CaptureVideo, Task, TaskCompleted, Alarm, Bookmark, Shuffle, Audio y Update. Si quisiéramos hacer uno que capturara vídeo, tendríamos que poner en el info.plist el valor UIApplicationShortcutIconTypeCaptureVideo siguiendo la nomenclatura del enum. Algunos solo están soportados en iOS 9.1.
  • UIApplicationShortcutItemSubtitle: Subtítulo, más pequeño, bajo el título indicado.
  • UIApplicationShortcutItemUserInfo: Un diccionario que podamos indicar opcionalmente, para incorporar algún tipo de dato auxiliar que quisiéramos que se enviara al usar esta opción rápida para invocar la app.

Si lo hemos hecho bien, y seguimos el ejemplo que indicamos aquí, podríamos tener estas dos opciones fijas declaradas desde el fichero info.plist.

info.plist 3D Touch

Pero, la segunda e importante parte de esta implementación es la captura de la entrada a la app y el redireccionamiento hacia dónde nos interesa. Por este motivo, ahora nos vamos al AppDelegate de nuestro proyecto y creamos una de las muchas versiones polimórficas que tenemos de la función application, en este caso la que usa el parámetro performActionForShortcutItem, quedando la llamada a la función de la siguiente forma:

Y ahora, el truco está en preguntar por el parámetro shortcutItem y la propiedad del mismo .type. Y lo que preguntamos es por la cadena UIApplicationShortcutItemType que hemos usado en el parámetro del fichero info.plist. Esta es la clave para identificar qué acceso rápido se ha usado una vez abrimos nuestra app.

De esta forma, capturamos los posibles valores de entrada que nos indican qué acceso rápido ha sido usado para acceder a nuestra app y, por lógica, habrá que actuar en consecuencia e implementar qué supone, como abrir una vista del storyboard en vez de otra, por ejemplo.

También podemos hacer estas acciones rápidas, programando y registrando estas a través de objetos UIApplicationShortcutItem que luego registramos en la propiedad de tipo array shortcutItems del singleton del sistema UIApplication.sharedApplication().

Hemos querido implementar el icono de la nube .Cloud en el icono del acceso rápido, pero este tipo está solo disponible en iOS 9.1, así que usamos la comprobación de versión intrínseca de iOS. Si estamos en iOS 9.1 o superior (comprobado con if #available(iOS 9.1, *)) entonces usamos .Cloud, pero si no, usamos .Compose. Y en ambos casos, asignamos a UIApplication.sharedApplication().shortcutItems el valor de convertir nuestra constante shortcut en un array.

Aunque al ser un array podemos poner más de un acceso rápido por programación (obviamente). Pero hemos de estar tranquilos, porque si pusimos algunos en el info.plist ambos seguirán en nuestra app y ninguno descarta al otro, si no que se suman.

One more thing, detectando la presión

Y antes de cerrar, no podemos dejar la ocasión de jugar con el valor analógico de la presión. Imaginemos que tenemos un juego donde nuestra velocidad de disparo en una nave dependerá del nivel de presión que hagamos en la pantalla. Pues la forma de obtener este dato es bien sencilla.

Lo único que debemos hacer es acceder a este dato a través de nuevas propiedades de UITouch. Utilizando las funciones normales de detección de toque, como touchesBegan o touchesMoved, podemos acceder a dos nuevas propiedades: force y maximumPossibleForce. La primera nos permite medir la fuerza del toque y la última el máximo valor que tendrá esta presión, para poder tener un límite del valor.

Lógicamente, comprobamos nuevamente que traitCollection.forceTouchCapability sea .Available para que descarte cuando no tengamos esta función disponible (usar esta comprobación no requiere conformarse a ningún protocolo). Y también, lógicamente, podemos seguir accediendo al punto donde estamos pulsando, además de a los valores de fuerza, por si queremos que el disparo sea en el punto donde estemos presionando.

3D Touch, el éxito de los gestos

Si hay una común opinión de todo aquel que ha probado el 3D Touch, es que solo por eso, los nuevos iPhone 6s y 6s Plus ya valen la pena. La facilidad y productividad que nos ofrecen es excelente, y con esta guía podemos ver lo fácil que resulta integrar estos gestos en nuestra app y ofrecer a nuestros usuarios una mejor interacción con nuestros desarrollos.

Siempre hay que estar al día, siempre hay que implementar todas las últimas funciones para ofrecer lo mejor a nuestros usuarios o clientes, y viendo lo sencillo que es hacerlo, no tenemos excusa. Y como siempre decimos, practicad, probad, experimentad… y Good Apple Coding.

Acerca de Julio César Fernández

Analista, consultor y periodista tecnológico, desarrollador, empresario, productor audiovisual, actor de doblaje e ingeniero de vídeo y audio.

Otras recomendaciones

Prototipos Unit Testing TDD

Lecciones por prototipos (II): test unitarios (XCTest y TDD)

Una de las cosas que normalmente se perciben más complejas en el desarrollo en cualquier …

  • Arturo Rivas Arias

    Excelente artículo. Completo y muy bien explicado. Muchas gracias!