Cómo hacer que una vista personalizada sea interactiva

Prueba el método de Compose
Jetpack Compose es el kit de herramientas de IU recomendado para Android. Obtén información para trabajar con diseños en Compose.

Diseñar una IU es solo una parte de la creación de una vista personalizada. También debes Haz que tu vista responda a la entrada del usuario de una manera que se parezca mucho a la real que estás imitando.

Haz que los objetos de tu app actúen como lo hacen los objetos reales. Por ejemplo, no dejes que las imágenes de tu app desaparecen y vuelven a aparecer en otro lugar, ya que los objetos en el mundo real no hagan eso. En cambio, mueve tus imágenes de un lugar a con el otro.

Los usuarios perciben un comportamiento o una sensación incluso sutiles en una interfaz y reaccionan mejor a sutilezas que imitan el mundo real. Por ejemplo, cuando los usuarios deslizan un objeto de IU, les dan una sensación de inercia al comienzo que retrasa el movimiento. Al final del movimiento, dales una sensación de momentum que lleva el objeto más allá del lanzamiento.

En esta página, se muestra la manera de usar las funciones del framework de Android para agregar estos comportamientos del mundo real a tu vista personalizada.

Puedes encontrar más información relacionada en Descripción general de los eventos de entrada y Animación de la propiedad descripción general.

Cómo controlar los gestos de entrada

Al igual que muchos otros marcos de trabajo de la IU, Android admite un modelo de evento de entrada. Usuario acciones se convierten en eventos que activan devoluciones de llamada, y puedes anular el de llamadas para personalizar la respuesta de tu app al usuario. La entrada más común evento en el sistema Android es el táctil, que activa onTouchEvent(android.view.MotionEvent) Anula este método para controlar el evento, como se indica a continuación:

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return super.onTouchEvent(event)
}

Java

@Override
   public boolean onTouchEvent(MotionEvent event) {
    return super.onTouchEvent(event);
   }

Los eventos táctiles por sí solos no son particularmente útiles. IU táctiles modernas definen las interacciones en términos de gestos como tocar, tirar, empujar, deslizar y hacer zoom. Para convertir eventos táctiles sin procesar en gestos, Android proporciona GestureDetector

Para crear un GestureDetector, pasa una instancia de una clase. que implementa GestureDetector.OnGestureListener Si solo quieres procesar algunos gestos, puedes extender GestureDetector.SimpleOnGestureListener en lugar de implementar GestureDetector.OnGestureListener interfaz de usuario. Por ejemplo, este código crea una clase que extiende GestureDetector.SimpleOnGestureListener y anulaciones onDown(MotionEvent)

Kotlin

private val myListener =  object : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
        return true
    }
}

private val detector: GestureDetector = GestureDetector(context, myListener)

Java

class MyListener extends GestureDetector.SimpleOnGestureListener {
   @Override
   public boolean onDown(MotionEvent e) {
       return true;
   }
}
detector = new GestureDetector(getContext(), new MyListener());

Ya sea que uses o no GestureDetector.SimpleOnGestureListener, implementar siempre un onDown() que muestre true. Esto es necesario porque todos los gestos comienza con un mensaje onDown(). Si devuelves false de onDown(), como Si GestureDetector.SimpleOnGestureListener lo hace, el sistema supone que quieres ignorar el resto del gesto y los demás métodos de No se llama a GestureDetector.OnGestureListener. Solo devolución false de onDown() si quieres ignorar un mensaje completo gesto.

Después de implementar GestureDetector.OnGestureListener y crear una instancia de GestureDetector, puedes usar tu GestureDetector para interpretar los eventos táctiles que recibes en onTouchEvent()

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return detector.onTouchEvent(event).let { result ->
        if (!result) {
            if (event.action == MotionEvent.ACTION_UP) {
                stopScrolling()
                true
            } else false
        } else true
    }
}

Java

@Override
public boolean onTouchEvent(MotionEvent event) {
   boolean result = detector.onTouchEvent(event);
   if (!result) {
       if (event.getAction() == MotionEvent.ACTION_UP) {
           stopScrolling();
           result = true;
       }
   }
   return result;
}

Cuando pasas a onTouchEvent() un evento táctil que no reconoce como parte de un gesto, muestra false. Luego, puedes ejecutar tu propio código personalizado de detección de gestos.

Crear movimientos físicamente posibles

Los gestos son una forma poderosa de controlar los dispositivos con pantalla táctil, pero pueden ser sean contradictorios y difíciles de recordar, a menos que produzcan resultados creíbles.

Por ejemplo, supongamos que quieres implementar un gesto de deslizamiento horizontal que establece el elemento dibujado en la vista que gira alrededor de su eje vertical. Este gesto tiene sentido si la IU responde moviéndose rápidamente en la dirección del lanzamiento, y luego se vuelve más lenta, como si el usuario empujara un volante y lo hiciera girar.

La documentación sobre cómo animar un pergamino brinda una explicación detallada sobre cómo implementar tu propio Scoll el comportamiento de los usuarios. Pero simular la sensación de un volante no es trivial. Mucha física y matemáticas para que un modelo de volante funcione correctamente. Afortunadamente, Android proporciona clases auxiliares para simular este y otros comportamientos. El Scroller es la base para controlar los gestos de desplazamiento tipo volante.

Para iniciar un lanzamiento, llama fling() con la velocidad inicial y los valores mínimos y máximos de x y de y valores del lanzamiento. Para el valor de velocidad, puedes usar el valor calculado por GestureDetector

Kotlin

fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
    scroller.fling(
            currentX,
            currentY,
            (velocityX / SCALE).toInt(),
            (velocityY / SCALE).toInt(),
            minX,
            minY,
            maxX,
            maxY
    )
    postInvalidate()
    return true
}

Java

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
   scroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY);
   postInvalidate();
    return true;
}

La llamada a fling() configura el modelo físico para el lanzamiento. gesto. Luego, actualiza el Scroller llamando a Scroller.computeScrollOffset() a intervalos regulares. computeScrollOffset() actualiza el El estado interno del objeto Scroller lee la hora actual y usando el modelo físico para calcular la posición y y x en ese tiempo. Llamada getCurrX() y getCurrY() para recuperar estos valores.

La mayoría de las vistas pasan x e y del objeto Scroller. posiciones directamente en scrollTo() Este ejemplo difiere un poco: utiliza la posición x de desplazamiento actual para configurar el ángulo de rotación de la vista.

Kotlin

scroller.apply {
    if (!isFinished) {
        computeScrollOffset()
        setItemRotation(currX)
    }
}

Java

if (!scroller.isFinished()) {
    scroller.computeScrollOffset();
    setItemRotation(scroller.getCurrX());
}

La clase Scroller calcula las posiciones de desplazamiento por ti, pero no aplica automáticamente esas posiciones a tu vista. Aplicar coordenadas nuevas con suficiente frecuencia para que la animación de desplazamiento se vea fluida. Hay dos maneras de haz lo siguiente:

  • Llama para forzar un nuevo diseño postInvalidate() después de llamar a fling(). Esta técnica requiere que de desplazamiento de Compute en onDraw() y llamar a postInvalidate() cada vez que se desplace el desplazamiento cambios.
  • Configura un ValueAnimator para animar durante el lanzamiento y agregar un objeto de escucha para procesar actualizaciones de animaciones llamando addUpdateListener() Esta técnica permite animar propiedades de un View

Cómo hacer que tus transiciones sean fluidas

Los usuarios esperan que una IU moderna realice una transición fluida entre estados: elementos de la IU un fundido de entrada y salida en lugar de aparecer y desaparecer, y los movimientos que comienzan y terminar sin problemas, en lugar de iniciarse y detenerse abruptamente. Android animación de propiedades de Terraform facilita las transiciones fluidas.

Para usar el sistema de animación, cada vez que una propiedad cambia lo que afecta tu la apariencia de la vista, no cambies la propiedad directamente. En cambio, usa ValueAnimator para realizar el cambio. En el siguiente ejemplo, modificar el componente secundario seleccionado en la vista hace que todo el o la vista rotativa para que el puntero de selección esté centrado. ValueAnimator cambia la rotación durante un período de varios cientos. en lugar de establecer de inmediato el nuevo valor de rotación.

Kotlin

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply {
    setIntValues(targetAngle)
    duration = AUTOCENTER_ANIM_DURATION
    start()
}

Java

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0);
autoCenterAnimator.setIntValues(targetAngle);
autoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION);
autoCenterAnimator.start();

Si el valor que quieres cambiar es uno de los View base propiedades, hacer la animación es aún más fácil porque las vistas tienen una ViewPropertyAnimator que está optimizado para la animación simultánea de múltiples propiedades, como en siguiente ejemplo:

Kotlin

animate()
    .rotation(targetAngle)
    .duration = ANIM_DURATION
    .start()

Java

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();