Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Android SDK
Code

Android SDK: Introducción a los gestos

Difficulty:IntermediateLength:LongLanguages:

Spanish (Español) translation by Elías Nicolás (you can also view the original English article)

Uno de los cambios más generalizados en el uso de dispositivos de pantalla táctil en los últimos años ha sido la adopción de gestos con los dedos, como los golpes y tiros. Permiten que la interacción entre el usuario y el dispositivo se convierta en una sensación muy intuitiva y natural. En este tutorial, aprenderá cómo comenzar a utilizar gestos en sus propias aplicaciones de Android.

Este tutorial utilizará el código proporcionado en un proyecto de código abierto. Los autores están asumiendo que el lector tiene alguna experiencia con Android y Java. Sin embargo, si tiene preguntas sobre lo que hemos hecho, no dude en preguntar.

Este tutorial le enseñará cómo comenzar a manejar gestos con los dedos dentro de sus aplicaciones. Haremos esto utilizando un dibujo de objeto Canvas básico en un objeto de vista personalizado. Esta técnica se puede aplicar a cualquier entorno gráfico que estés usando, ya sea una superficie 2D o incluso el renderizado de OpenGL ES. Si te interesan los gestos multitáctiles (un tema más avanzado de manejo de gestos), lo veremos en otro tutorial próximo.

Paso 0: Creando el Proyecto

Comencemos simple. Crea un nuevo proyecto de Android. Nombramos nuestro proyecto Gesture Fun y configuramos su única actividad, que se llama GestureFunActivity. Modifique el archivo de diseño predeterminado, main.xml, al siguiente diseño muy básico:

El elemento importante en este diseño es la definición de FrameLayout. El control FrameLayout se usa para mantener la vista personalizada que dibujará una imagen.

Finalmente, actualicemos el método onCreate() de la clase Activity para inicializar el control FrameLayout y proporcionarle algo de contenido:

En este punto, aún no hemos definido la clase PlayAreaView, por lo que el proyecto no se compilará. Ten paciencia, llegaremos a esto en el siguiente paso.

Paso 1: Creando una nueva vista: PlayAreaView

Con toda la configuración de nuestro proyecto fuera del camino, ahora podemos enfocarnos en la parte interesante: dibujar en el objeto Canvas. Una forma fácil de hacer que un objeto Canvas se dibuje es anular el método onDraw() de un objeto View. Convenientemente, este método tiene un solo parámetro: el objeto Canvas. Dibujar un gráfico de mapa de bits en un objeto Canvas es tan fácil como llamar al método drawBitmap() del objeto Canvas. Este es un ejemplo simple de una implementación del método onDraw(), tal como se define en nuestra nueva clase PlayAreaView:

Nuestra implementación del método onDraw() es bastante básica. Como de costumbre, deberá definir su variable de etiqueta de registro DEBUG_TAG en algún lugar de su actividad. La mayor parte del método onDraw() es solo salida informativa. El único trabajo real realizado en este método tiene lugar en la llamada drawBitmap(), donde el primer parámetro es la imagen a dibujar. El segundo parámetro es un objeto Matrix llamado translate que, como su nombre lo indica, determina dónde se dibujará el mapa de bits en relación con la Vista en la que reside el objeto Canvas. Todo el resto del código en este tutorial involucrará la manipulación de la Matriz de traducción en función de ciertos eventos táctiles del usuario. Esto, a su vez, cambiará donde el objeto de mapa de bits se dibuja dentro del lienzo y, por lo tanto, en la pantalla.

Paso 2: Configuración de la nueva vista

La clase PlayAreaView necesita un constructor para realizar una configuración inicial. Dado que nuestra Vista personalizada deberá reaccionar a los gestos, necesitamos un GestureDetector aquí. Un GestureDetector es una clase de Android que puede tomar eventos de movimiento, hacer algo de magia matemática para determinar qué son y luego delegar llamadas a un objeto GestureListener como un gesto específico u otras devoluciones de llamada de movimiento. El objeto GestureListener, una clase que implementamos, recibe estas llamadas para gestos específicos que el GestureDetector reconoce y nos permite reaccionar ante ellos como lo creamos (en este caso, para mover un gráfico dentro de nuestro PlayAreaView). Aunque GestureDetector maneja la detección de ciertos movimientos, no hace nada específico con ellos ni maneja todo tipo de gestos. Sin embargo, para los fines de este tutorial, proporciona información suficiente. Entonces, vamos a conectarlo:

Veamos el constructor PlayAreaView con un poco más de detalle. Primero, inicializamos la Matriz de traducción a una matriz de identidad (la opción predeterminada). Recuerde que una matriz de identidad no realizará modificaciones en un mapa de bits: se dibujará en su ubicación original.
A continuación, creamos e inicializamos el GestureDetector, uno predeterminado, y le asignamos un objeto GestureListener válido (hablaremos más sobre esto en un momento). Finalmente, el dibujable de mapa de bits, llamado droid, se carga directamente desde los recursos del proyecto. Puedes usar cualquier imagen que desees: una pelota de béisbol, una manzana, una galleta de la fortuna, etc. Este es el gráfico que estarás lanzando sobre el objeto Canvas.

Paso 3: Conectando el GestureDetector

Iremos al GestureListener a continuación, ya que es un objeto personalizado. Por ahora, conectemos el objeto GestureDetector para que reciba los datos de movimiento que necesita para hacer su gesto de reconocimiento de magia.

Ahora conectemos el objeto GestureDector llamado gestos para recibir eventos. Para hacer esto, anule el método onTouchEvent() del control View dentro de la clase PlayAreaView de la siguiente manera:

Lo que hemos hecho aquí es hacer del GestureDetector la última palabra en todos los eventos táctiles para esta vista personalizada. Sin embargo, el GestureDetector en realidad no hace nada con los eventos de movimiento, simplemente los reconoce y realiza una llamada a la clase GestureListener registrada.

Paso 4: Implementando un oyente de gestos

Para reaccionar ante los eventos reconocidos por la clase GestureDetector, necesitamos implementar la clase GestureListener. Los eventos de movimiento que más nos interesan son toques y gestos dobles de cualquier tipo. Para escuchar estos tipos de eventos de movimiento, nuestra clase GestureListener debe implementar las interfaces OnGestureListener y OnDoubleTapListener.

Después de agregar esta clase como una subclase de la Actividad, agregue implementaciones predeterminadas para cada uno de los métodos requeridos. Por ejemplo, aquí hay una implementación para el método onDown():

La implementación de estos métodos le permite estudiar los diversos eventos a medida que son reconocidos por el objeto GestureDetector. Curiosamente, si el método onDown() no devuelve verdadero, el gesto principal en el que estamos interesados ​​aquí (desplazamiento (o arrastre)) no se detectará. Sin embargo, puede devolver falso para los otros eventos reconocidos que no le interesan.

El objeto MotionEvent que se pasa como parámetro a cada método de devolución de llamada a veces representa el evento táctil que inició el reconocimiento de gestos y otras veces el último evento que completó el reconocimiento de gestos. Para nuestros propósitos, permitimos que la clase GestureDetector maneje todos los detalles de descifrar qué tipo de movimiento representa el MotionEvent.

Nota: el marco de Android también proporciona una clase de conveniencia llamada SimpleOnGestureListener que combina las dos interfaces (OnGestureListener y OnDoubleTapListener) en una sola clase con implementaciones predeterminadas para todos los métodos. Las implementaciones por defecto devuelven falso.

Paso 5: Manejo de eventos de movimiento simple

El primer evento que nos gustaría manejar es el evento de desplazamiento. Se produce un evento de desplazamiento cuando el usuario toca la pantalla y luego mueve su dedo sobre ella. Este gesto también se conoce como un evento de arrastre. Este evento se produce a través del método onScroll() de la interfaz OnGestureListener.

Aquí está la implementación del método onScroll():

Utilice el evento de desplazamiento para pasar una solicitud de movimiento al objeto PlayAreaView. La implementación de este método es un primer paso importante en el mapeo de cómo un evento de movimiento con el dedo provoca el movimiento gráfico. Llegaremos a esto en breve. Mientras tanto, ¡has controlado tu primer gesto!

El gráfico se moverá por toda la pantalla y, a veces, incluso fuera de él. Por definición, la imagen solo es visible cuando se dibuja dentro de los límites del objeto Vista. Si las coordenadas de los gráficos caen fuera de los límites del objeto de Vista, el gráfico se recorta (no se ve). Podrías poner Detección de bordes y varios otros bits de lógica (más allá del alcance de este tutorial, nos tememos), o simplemente agregar detección para tocar dos veces y restablecer la ubicación del gráfico. Aquí está la implementación de ejemplo del método onDoubleTap() (de la interfaz OnDoubleTapListener):

Al igual que con la implementación del método anterior, estamos utilizando este movimiento reconocido, un doble toque, para activar un cambio dentro de nuestro control de vista. En este caso, simplemente restablecemos la ubicación de la vista.

Paso 6: Lanzando Cosas

Un gesto de lanzamiento es, esencialmente, dejar la velocidad en un elemento que se estaba arrastrando a través de una pantalla. El elemento en movimiento generalmente se ralentizará gradualmente, pero este comportamiento es dictado por la implementación del desarrollador. En un juego, por ejemplo, la velocidad podría estar sujeta a la física del mundo del juego. En otras aplicaciones, la velocidad podría basarse en la fórmula que se sienta adecuada para la acción que representa. La prueba es la mejor manera de tener una idea de cómo se siente. En nuestra experiencia, se necesita algo de prueba y error para resolver algo que se siente y se ve bien.

En nuestra implementación, variaremos el tiempo que transcurre antes de que se detenga el movimiento causado por el lanzamiento, y luego simplemente iniciaremos una animación de la imagen al destino final en función de la velocidad que el método onFling() nos transmite y La cantidad de tiempo que fijamos. Recuerde, el gesto de lanzamiento no se detecta hasta que el dedo del usuario ya no toca la pantalla. Piense en ello como tirar una roca: la roca continúa viajando cuando la suelta; esta es la parte que queremos animar una vez que el usuario "se vaya".

¿Suena complejo? Aquí está el código:

Ni siquiera necesitamos examinar los dos parámetros de MotionEvent, los datos de velocidad son suficientes para nuestros propósitos. Las unidades de velocidad están en píxeles por segundo. Por lo tanto, podemos usar los datos de velocidad para decidir el factor de escala que se usará para determinar el tiempo final antes de que la imagen se detenga por completo. En nuestro caso, estamos utilizando el 40% de un segundo (400 ms). Entonces, al multiplicar la mitad de los dos valores de velocidad por 40% (también conocida como la variable distanceTimeFactor), encontramos el movimiento total alcanzado después de esta fracción de segundo. Finalmente, pasamos esta información a nuestro método onAnimateMove() personalizado del objeto Ver, que en realidad hará que nuestro gráfico parezca moverse en la pantalla utilizando la información proporcionada por el evento de movimiento de tiro.

¿Por qué la mitad de la velocidad inicial? Si empezamos a, digamos, la velocidad A y terminamos a la velocidad B durante un período de tiempo, la velocidad promedio es (A + B) / 2. En este caso, la velocidad final es 0. Por lo tanto, recortamos la velocidad a la mitad aquí para no hacer que la imagen parezca que salta de nuestro dedo más rápido de lo que lo estaba haciendo antes de que la lanzáramos.

¿Por qué 400 ms? No hay ninguna razón en absoluto, pero se ve bastante bien en la mayoría de los dispositivos. No es diferente a calibrar los movimientos de tu mouse: demasiado rápido y se siente nervioso y difícil de ver, demasiado lento y estás esperando a que tu lento ratón se ponga al día con tu cerebro. Este valor es la variable principal para ajustar la "sensación" de su aventura. Cuanto mayor sea el valor, menos "fricción" parecerá tener la imagen cuando se desliza hasta detenerse en la pantalla. Si tiene variaciones reales en la superficie, deberá aplicar cálculos físicos regulares. Aquí, solo estamos haciendo una función fija más lenta sin ningún tipo de física real.

Paso 7: Moviendo la imagen

Ahora que todos los gestos que nos interesan en el área manejada, es hora de implementar el movimiento real del gráfico subyacente. De vuelta en la clase PlayAreaView, agregue el método onMove():

Este método hace dos cosas. Primero, traduce (traduce = término de gráficos para moverse del punto A al punto B) nuestra propia matriz por la distancia que el dedo movió. Luego invalida la vista para que se vuelva a dibujar. Al dibujar, la imagen se dibujará en una ubicación diferente dentro de la vista. Si hubiéramos querido desplazar todo el objeto Vista, podríamos utilizar el método translate() del objeto Vista para actualizar su matriz interna utilizada por su Lienzo para realizar todo el dibujo. Esto podría funcionar bien para algunas cosas, pero si tuviéramos algo estático (por lo que queremos decir fijo, inmóvil, inmóvil, como montañas) dentro de la vista, no lo haría. En su lugar, para este caso, solo actualizamos nuestra propia Matriz, traducción, que usamos cada vez que dibujamos el gráfico.

Ahora agregamos el método onResetLocation() también:

Este método simplemente restablece la matriz a la matriz de identidad y hace que la vista se vuelva a dibujar a través del método invalidate(). Cuando se redibuje la vista, el gráfico volverá a su posición inicial.

Paso 8: Mover suavemente la imagen

Para el movimiento de lanzamiento, tenemos algo más que hacer que dibujarlo en una nueva ubicación. Queremos que se anime perfectamente a esa posición. Se puede lograr un movimiento suave a través de la animación, es decir, dibujar la imagen en un lugar diferente muy rápidamente. Android tiene clases de animación incorporadas, pero se aplican a vistas completas. No estamos animando un objeto de vista. En cambio, estamos moviendo una imagen en el Lienzo controlado por una Vista. Entonces, tenemos que implementar nuestra propia animación. Maldicion. ☺

Android proporciona diferentes interpoladores para ayudar a ajustar la ubicación de un objeto en el momento específico durante las animaciones utilizando las clases de animación incorporadas. Podemos aprovechar estos diferentes interpoladores dentro de nuestra propia animación para ahorrar un poco de trabajo y aplicar algunos efectos divertidos. Esto es posible porque los interpoladores proporcionados son muy genéricos y no están ligados a los aspectos específicos de cómo funcionan las animaciones de vista integradas.

Comencemos con el método onAnimateMove():

En este método, rastreamos la ubicación de inicio, la hora de inicio y las horas de finalización.

Aquí, inicializamos nuestra animación usando la clase OvershootInterpolator. Como este interpolador hace que la imagen se mueva un poco más lejos, en general, de lo que calculamos, la imagen técnicamente comenzará un poco más rápido. Es una diferencia lo suficientemente pequeña como para que no se note, pero si buscaba precisión, tendría que ajustarse a eso (lo que significaría escribir su propio interpolador,
más allá del alcance de este tutorial (y con un método para calcular la distancia total recorrida).

Toda esta información se utiliza para determinar cuándo (en el tiempo) estamos a lo largo de la duración total de la animación. Utilizamos estos datos para determinar cuándo (en porcentaje de tiempo) debemos pasar esta información al interpolador. El interpolador necesita esto para que nos diga dónde (en porcentaje de distancia) estamos desde el punto de inicio hasta el punto final de nuestro movimiento. Usamos esto, a su vez, para determinar dónde estamos (en píxeles) desde el punto de partida.

Este cálculo se hace todo en el método onAnimateStep(), que se muestra a continuación. Llamamos al método onAnimationStep() a través de una publicación en la cola de mensajes. No queremos entrar en un circuito cerrado, haríamos que el sistema no responda. Por lo tanto, una forma sencilla es simplemente publicar los mensajes. Esto permite que el sistema siga respondiendo al proporcionar un comportamiento asíncrono sin tener que lidiar con los hilos. Como tenemos que hacer nuestro dibujo en el subproceso de la interfaz de usuario, de todos modos, hay un pequeño punto en este simple ejemplo.

Ahora implementemos el método onAnimateStep():

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.