Microinteracciones en iOS. Conferencia de Yandex

Hace unas semanas, se celebró un evento especial de la comunidad CocoaHeads en la oficina de Yandex, más grande que los mitaps tradicionales. El desarrollador Anton Sergeyev habló en esta reunión y habló sobre el modelo de microinteracción que los diseñadores de UX suelen usar, así como sobre cómo poner en práctica las ideas. Anton prestó más atención a la animación.


- Es muy importante para mí que fue un honor conocer a los invitados. Veo aquí a aquellos con quienes he conocido por mucho tiempo, aquellos con quienes he conocido recientemente y aquellos con quienes aún no me he reunido. Bienvenido a CocoaHeads.

Te contaré sobre micro interacciones. Esto es un poco de clickbait: somos ingenieros, desarrolladores, hablaremos más sobre la parte del software, pero comenzaremos con un tema muy humanitario, como las micro interacciones. Como resultado, aplicaremos este tema humanitario en la parte técnica para aprender a diseñar de manera más eficiente y simple componentes visuales muy pequeños, como botones, cargadores pequeños, barras. Están saturados de animación, y el código de animación ramificado a menudo puede parecer muy complicado, es extremadamente difícil de mantener.

Pero primero, un poco de distracción. Piénselo, ¿recuerda cuándo decidió convertirse en desarrollador? Claramente lo recuerdo. Todo comenzó con una mesa. Una vez decidí aprender ObjC. Lenguaje de moda, divertido, así, sin planes de largo alcance. Al parecer, encontré un libro, Big Nerd Ranch, y comencé a leer capítulo por capítulo, haciendo cada ejercicio, revisando, leyendo, hasta que llegué a la mesa. Luego, primero me familiaricé con el patrón de delegado, más precisamente con su subespecie "Fuente de datos", fuente de datos. Este paradigma me parece muy simple ahora: hay una fuente de datos, delegado, todo es simple. Pero luego me dejó alucinado: ¿cómo puedo separar una tabla de datos completamente diferentes? Una vez viste una tabla en una hoja de papel en la que puedes poner un número infinito de filas, datos completamente abstractos. Me influyó mucho. Me di cuenta de que la programación, el desarrollo tiene enormes oportunidades, y será muy interesante aplicarlas. Desde entonces, decidí convertirme en desarrollador.

Durante el desarrollo, se encontraron varios patrones. Enormes, que se llaman arquitecturas que describen toda la aplicación. Pequeños que caben en docenas en un pequeño botón. Es importante comprender que todos estos patrones no provienen del aire, sino del sector humanitario. El mismo patrón de delegado. La delegación apareció mucho antes de la programación, y la programación se hace cargo de todas estas cosas humanitarias para un trabajo más eficiente.

Hoy hablaré sobre otro enfoque que se hace cargo de otra cosa humanitaria. En particular, sobre micro interacciones.

Todo comenzó con un cargador. En el trabajo anterior, antes de Yandex, tuve la tarea de repetir el cargador de diseño de materiales de Google. Hay dos de ellos, uno indefinido, el otro definido. Tuve la tarea de combinarlos en uno, tenía que ser capaz de ser cierto e indefinido, pero había requisitos estrictos, por lo que era extremadamente suave. En cualquier momento, podemos movernos de un estado a otro, y todo debe ser animado de manera fluida y precisa.

Soy un desarrollador inteligente, hice todo. Obtuve más de 1000 líneas de código de fideos incomprensible. Funcionó, pero recibí un comentario genial sobre la revisión del código: "Realmente espero que nadie edite este código". Y para mí es prácticamente inadecuado. Escribí un código horrible. Funcionó bien, fue una de mis mejores animaciones, pero el código fue horrible.

Hoy trataré de describir el enfoque que encontré después de dejar ese trabajo.



Comencemos con el tema más humanitario: los modelos de microinteracción. ¿Cómo están incrustados y, en general, dónde están ocultos en nuestras aplicaciones? Continuemos usando este modelo en nuestro mundo técnico. Considere cómo UIView, que se ocupa de la visualización y la animación, cómo funciona esto. En particular, hablaremos mucho sobre el mecanismo de CAAction, que está estrechamente integrado y funciona con UIView, CALayer. Y luego considere pequeños ejemplos.

Definición primero. Aparentemente, al autor realmente le gustó el prefijo "micro", pero no hay macro o nano interacciones, el tamaño no importa. Por simplicidad, los llamaremos simplemente interacciones. Este es un modelo tan conveniente que le permite describir cualquier interacción con la aplicación, de principio a fin. Consta de cuatro puntos: un desencadenante, lógica empresarial que debe implementarse en esta interacción, comentarios para transmitir algo al usuario y un cambio en el estado de la aplicación.

Contaré una historia con tres roles diferentes. Comenzaré con el usuario, como lo más importante en el desarrollo. Cuando me estaba preparando para el informe, me enfermé. Necesitaba encontrar una farmacia y abrí Yandex.Map. Abrí la aplicación, la miro, me mira, pero no pasa nada. Luego me di cuenta de que yo era el usuario, soy el principal, doy instrucciones sobre qué hacer con la aplicación. Me orienté, hice clic en el botón "buscar", ingresé en "farmacia", hice clic en "Aceptar", la aplicación realizó el trabajo interno, encontró las farmacias necesarias que estaban a mi lado y las visualicé en la pantalla.

Busqué el correcto y descubrí que, además de las farmacias, aparecía un botón especial en la pantalla para construir una ruta. Por lo tanto, la aplicación se ha movido a un nuevo estado. Hice clic en él y fui a la farmacia. Entré en esta aplicación por alguna razón: para encontrar una farmacia. La alcancé. Soy un usuario feliz

Antes de que apareciera esta aplicación, y pude buscar algo en ella, primero se desarrolló. ¿Qué pensó el diseñador de UX cuando se le ocurrió este proceso? Todo comenzó con el hecho de que era necesario salir de una escena muda cuando el usuario y la aplicación se miran, y no sucede nada. Para esto, se necesitaba algún tipo de disparador. Todo tiene un comienzo, y aquí, también, fue necesario comenzar en alguna parte.

Se ha seleccionado el disparador: botón de búsqueda. Al hacer clic en él, era necesario resolver el problema desde un punto de vista técnico. Solicite datos en el servidor, analice la respuesta, actualice de alguna manera el modelo, analice. Solicite la posición actual de los usuarios y más. Entonces obtuvimos estos datos y sabemos exactamente dónde están todas las farmacias.

Parece que fue posible terminar con esto. Después de todo, resolvimos el problema, encontramos todas las farmacias. Solo hay un problema: el usuario aún no sabe nada sobre estas farmacias. Necesita comunicarlo.

De alguna manera empacar nuestra solución a este problema y llevarlo a él en un paquete hermoso para que lo entienda. Dio la casualidad de que los usuarios son personas, interactúan con el mundo exterior a través de los sentidos. El estado actual de la tecnología es tal que nosotros, como desarrolladores de aplicaciones móviles, tenemos solo tres sentidos: visión, podemos mostrar algo en la pantalla, audición, podemos reproducir en los altavoces y una sensación táctil, podemos empujar al usuario en la mano.

Pero el hombre es mucho más funcional. Pero el estado actual de la tecnología es tal que por el momento solo podemos confiar en estos tres. Y en este caso seleccionamos una pantalla, mostramos en el mapa las farmacias más cercanas y con una lista con información más detallada sobre estas farmacias. Y parece que esto es exactamente todo, el usuario encontró farmacias y todo está bien.

Pero hay un problema. Cuando el usuario ingresó a la aplicación, se encontraba en un contexto en el que no sabía dónde estaban ubicadas las farmacias. Y sus tareas eran encontrarla. Pero ahora el contexto ha cambiado, él sabe dónde están las farmacias, ya no necesita buscarlas. Tenía la siguiente tarea: obtener instrucciones para llegar a la próxima farmacia. Es por eso que necesitamos mostrar controles adicionales en la pantalla, en particular, este es un botón para construir una ruta, es decir, transferir la aplicación a otro estado en el que esté lista para aceptar nuevos desencadenantes para las próximas interacciones nuevamente.

Imagínese, el diseñador de UX se le ocurrió todo esto, llega al desarrollador y comienza a describir en colores cómo el usuario hace clic en el botón, cómo y qué sucede, cómo se busca, cómo el usuario está contento, cómo aumentamos la DAU, etc. La pila de preguntas no resueltas del desarrollador se desbordó en otro lugar en la primera oración, cuando mencionamos por primera vez el botón.

Escucha pacientemente todo, y al final, cuando termina, dice que está bien, esto es genial, pero discutamos el botón. Este es un elemento importante.

Durante la discusión, resulta que el botón es inherentemente un disparador, contiene lógica dentro de sí mismo, por lo que puede recibir mensajes del sistema, en particular, sobre los clics del usuario en la pantalla. En función de este clic, puede iniciar una cadena de eventos, que comienza con el hecho de que el mismo botón envía mensajes a diferentes objetos sobre la necesidad de iniciar varios procesos, en este caso, solicitar información en el servidor, un poco más.

Cuando se presiona, el botón cambia su estado, se presiona. Cuando el usuario libera, deja de presionarse. Es decir, proporciona comentarios al usuario para que comprenda qué esperar de este botón. Y el botón se puede presionar, no presionar, activo o inactivo, en diferentes estados, y moverse de acuerdo con una lógica diferente de un estado a otro.

Por lo tanto, vimos que el mismo modelo de microinteracción, que consiste en un disparador, lógica empresarial, retroalimentación y cambios de estado, puede describir nuestra aplicación en varias escalas, como en la escala de un caso de usuario completo, una gran búsqueda de la farmacia más cercana, así que en términos de un pequeño botón.

Y este es un modelo muy conveniente que le permite simplificar la interacción dentro del equipo y describir mediante programación cuatro entidades separadas: disparador, lógica de negocios, retroalimentación y cambio de estado. Veamos qué nos proporciona UIKit para usarlo. Y no solo proporciona, sino que usa. Al implementar varias animaciones, los pequeños componentes de las subclases de UIView, solo usa este mecanismo y no funciona de manera diferente.

Comencemos con UIView, cómo encaja en este modelo. Luego consideraremos CALayer que nos brinda para apoyar estos estados, y consideraremos el mecanismo de acciones, el momento más interesante.

Comencemos con la UIView. Lo usamos para mostrar algunos rectángulos en la pantalla. Pero, de hecho, UIView no sabe cómo dibujarse, utiliza otro objeto CALayer para esto. De hecho, UIView se compromete a recibir mensajes sobre tocar el sistema, así como sobre otras llamadas, sobre la API que definimos en nuestras subclases de UIView. Por lo tanto, UIView implementa la lógica de activación, es decir, el lanzamiento de algunos procesos, recibiendo estos mensajes del sistema.

UIView también puede notificar a sus delegados sobre los eventos que han ocurrido, y también enviar mensajes a los suscriptores, como, por ejemplo, hacer que UIControl subclases diferentes eventos. De esta manera, se implementa la lógica de negocios de esta UIView. No todos tienen lógica empresarial, muchos de ellos son solo elementos de visualización y no tienen retroalimentación en el sentido de la lógica empresarial.



Analizamos dos puntos, un disparador y una lógica empresarial. ¿Y dónde están escondidos los comentarios y el cambio de estado en UIView? Para entender esto, debemos recordar que UIView no existe por sí mismo. Cuando se crea, crea una capa de fondo, una subclase de CALayer.



Y se nombra a sí mismo su delegado. Para comprender cómo UIView usa CALayer, puede existir en varios estados.

¿Cómo distinguir un estado de otro? Difieren en el conjunto de datos que deben almacenarse en algún lugar. Consideraremos qué características nos proporciona CALayer para UIView, para que almacene el estado.



Nuestra interfaz se está expandiendo un poco, la interacción entre UIView y CALayer, UIView tiene una tarea adicional: actualizar el repositorio dentro de CALayer.

Un hecho poco conocido que pocas personas usan: CALayer puede comportarse como una matriz asociativa, lo que significa que podemos escribir datos arbitrarios en cualquier tecla de la siguiente manera: setValue (_: forKey :).



Este método está presente en todas las subclases de NSObject, pero a diferencia de muchos otros, cuando se recibe una clave que no se anula, no se bloquea. Y lo escribe correctamente, y luego podemos leerlo. Esto es algo muy conveniente, que permite, sin crear subclases de CALayer, escribir datos allí y luego leerlos, consultarlos. Pero este es un repositorio simple muy primitivo, de hecho, un diccionario. CALayer es mucho más progresivo. Es compatible con los estilos.

Esto se implementa mediante la propiedad Style que tiene cualquier CALayer. Por defecto, es nulo, pero podemos redefinirlo y usarlo.



En general, este es un diccionario normal y nada más, pero tiene una peculiaridad sobre cómo CALayer trabaja con él, si solicitamos valor para Key, otro método que tiene NSObject. Actúa de manera muy interesante, busca los valores necesarios en el diccionario de estilo de forma recursiva. Si empaquetamos un estilo existente en un nuevo estilo con la tecla de estilo y escribimos algunas teclas allí, pero se verá de la siguiente manera.



Primero, mire la raíz, luego tierra adentro y así sucesivamente, hasta que tenga sentido. Cuando el estilo se vuelve nulo, entonces no tiene sentido mirar más allá.

De esta manera, UIView puede, utilizando la infraestructura que proporciona CALayer, organizar cambios de estado, actualizar el repositorio interno de CALayer, ya sea usando estilo, un repositorio muy poderoso que puede simular una pila, o usando una matriz asociativa regular, que también es muy eficiente y muy útil. .

Terminado con almacenamiento, comience con CAAction. Te contaré más sobre él.



Hay una nueva tarea para UIView: solicitar acciones de CALayer. ¿Qué son las acciones?



CAAction es solo un protocolo que tiene un solo método: ejecutar. A Apple generalmente le encantan los temas de cine, la acción aquí como "cámara, motor". Este "motor" es solo una acción, y no solo se usó ese nombre. El método de ejecución significa iniciar una acción que puede iniciar, ejecutar y finalizar, que es lo más importante. Este método es muy genérico, solo tiene una cadena de eventos y todo lo demás puede ser de cualquier tipo. En ObjC, todo esto es id y un NSDictionary normal.



Hay clases dentro de UIKit que satisfacen el protocolo CAAction. El primero es la animación. Primero, sabemos que la animación se puede agregar a una capa, pero esto es algo de muy bajo nivel. Una abstracción de alto nivel por encima es ejecutar una acción con los parámetros necesarios con una capa.

La segunda excepción importante es NSNull. Sabemos que no puede ser llamado por ningún método, pero cumple con el protocolo CAAction, y esto se hace para buscar convenientemente CAAction en capas.



Como dijimos antes, UIView es un delegado a CALayer, y uno de los métodos de delegado es action (for: forKey :). La capa tiene un método, acción para Key.



Podemos llamarlo en cualquier momento en la capa, y en cualquier momento dará la acción correcta o nula, ya que también puede dar. El algoritmo es una búsqueda muy inusual. El pseudocódigo está escrito aquí, echemos un vistazo a las líneas. Al recibir dicho mensaje, primero consulta con el delegado. Un delegado puede devolver nulo, lo que significa que la búsqueda debe continuar en otro lugar, o puede devolver una acción válida, un objeto válido que satisfaga el protocolo CAAction. Pero hay una regla lógica: si devuelve NSNull, que satisface este protocolo, luego se convertirá en nulo. Es decir, si devolvemos Null, de hecho significará "dejar de buscar". No hay acción y no es necesario.

Pero hay lo siguiente. Después de consultar con el delegado y el delegado regresó nulo, continuó buscando. Primero, en el diccionario de acciones, que tiene la capa, y luego buscará recursivamente en el diccionario de estilos, donde también puede haber un diccionario con la tecla de acciones, en el que se pueden escribir muchas acciones, y también podrá buscarlas recursivamente. Si eso no funcionó, le pedirá a la clase la acción predeterminada para el método Key, que está definido por CALayer y hasta hace poco devolvió algo, pero últimamente siempre devuelve nil en las últimas versiones de iOS.

Entendió la teoría. Veamos cómo se aplica todo en la práctica.

Hay eventos, tienen claves, algunas acciones tienen lugar en estos eventos. Básicamente, se pueden distinguir dos tipos diferentes de eventos. El primero es la animación de las propiedades almacenadas. Supongamos que cuando llamamos Viewcolor = red en View, teóricamente es posible animar.



¿Qué informe sobre patrones sin circuito? Dibujé una pareja. UIView tiene algún tipo de interfaz que hemos definido para subclases o una que se recibe del sistema con eventos. La tarea de UIView es solicitar la acción deseada, actualizar el almacén interno e iniciar la acción que ocurrió. El orden es muy importante con respecto a la solicitud: acción, solo luego actualice la acción, y solo luego actualice la tienda y la acción.



¿Qué sucede si en UIView actualizamos backgroundColor? Sabemos que en UIView todo lo relacionado con la visualización en pantalla sigue siendo un proxy para CALayer. Guarda en caché todo lo que recibe, por si acaso, pero al mismo tiempo todo transmite CALayer, y se ocupa de toda la lógica en CALayer. ¿Qué sucede dentro de CALayer cuando recibe una tarea para cambiar el fondo? Aquí todo es un poco más complicado.



Para empezar, pedirá acción. Y es importante comprender que la acción se solicitará primero. Esto le permitirá preguntar a CALayer sus valores actuales, incluido backgroundColor, en el momento de crear la acción, solo entonces la tienda se actualizará, y cuando la acción recibida reciba el comando de ejecución, podrá consultar CALayer y obtener nuevos valores. Por lo tanto, poseerá tanto lo antiguo como lo nuevo, y esto le permitirá crear animación, si es necesario.

Pero hay una característica en UIView, si cambiamos el color de fondo en UIView, si hacemos esto en el bloque de animación, entonces está animado, y si está fuera del bloque de animación, no está animado.



Todo es muy simple, no hay magia. Pero solo recuerde que UIView es un delegado de CALayer, tiene ese método. Todo es muy sencillo.

Si este método se ejecutó en el bloque de animación, devolverá algún tipo de acción. Si está fuera del bloque de animación, este método devolverá NSNull, lo que significa que no es necesario animar nada. , CALayer .

, UIView , . . ?



, . UIView , read only, , inheritedAnimationDuration. . , . .

? duration, . , run, , .



, CAAction, backgroundcolor opacity, UIView . , , , , . . setValue forKey , , , , , , .

, , , , .

— . , «» «» . .

.



. , , , . UIView CALayer, , , CAAction, , , .





, , , . , . .

. - .

CAAction, , . , , , .



, , , home, . , . , .



. - .



, - , - . , , . , .

, , .



, CAAction , . , UIControl, - , - , , , - .

, . , UIView -, , - , , , .

— . .

? . , . — . activating, inactive active. , , .



. , onOrderIn onOrderOut. , UIKit, .

, -, — , .



. UIView , : isActive progress. . CAAction, .

, . , , 30 CAACtion, . , 30 , NSNull. 15 15 . . — . , — .

, . .

. , , : , -, .

, , . . , UIKit , . . , , , . Gracias por su atencion

Source: https://habr.com/ru/post/es429580/


All Articles