Cómo implementar elegantemente la vista previa de imágenes de iOS en Android
Enlace a la publicación original del blog
Cualquiera que haya usado iOS sabe que los efectos similares al rebote físico son muy comunes en iOS, porque se trata de un conjunto de marcos de interfaz de usuario compatibles con el sistema iOS. , pero no es así en Android. Tome el visor de imágenes como ejemplo. El efecto en iOS es que la imagen está vinculada a un dispositivo de resorte y el deslizamiento es muy natural, pero Android no tiene un visor de imágenes. Android no viene con un visor de imágenes, debes implementarlo tú mismo
Los visores de imágenes convencionales en el mercado no tienen el efecto de rebote, por un lado porque no tienen esa necesidad, y por otro. por otro lado, porque es bastante problemático de implementar. Aquí hay un programa que creo que es el mejor.
Un visor de imágenes, que requiere que puedas deslizar Fling, rebotar al tocar el límite, rebotar. al cruzar el límite, admite zoom con dos dedos y escala con doble clic.
A primera vista, este requisito debería ser fácil de escribir. El desplazamiento se resuelve con Scroller y el efecto de rebote se resuelve directamente con ValueAnimator. y el interpolador se establece en un interpolador de desaceleración. Parece simple, pero debido a que es un efecto físico, implica el tiempo desde el desplazamiento hasta el rebote (la animación del desplazamiento cambia a la animación ValueAnimator) y problemas de velocidad de conexión. Es necesario asegurarse de que no haya cambios repentinos desde el comienzo del desplazamiento hasta el final. al final del rebote. El procesamiento de límites de juicio especial en el medio es muy problemático y también implica escalar, por lo que no considero esta opción.
Ya que queremos simular los efectos físicos en la realidad. ¿Por qué no obtener la aceleración en cada cuadro en función del estado actual y luego calcular la aceleración en el siguiente cuadro? De esta manera, siempre que la aceleración física en la realidad no se pueda simular, esos juicios especiales de límites pueden ir al Rey. del Infierno
Una vez determinado el plan, el siguiente paso es seleccionar la ecuación de aceleración para simular el efecto de la fuerza de tracción es simple, use la ley de Hooke. Muy simple, ¡usa la ley de Hooke! F = k * dx, ¿fricción? Ff = μ * FN? Aquí recomendamos un programa mejor, tome prestada la biblioteca Rebound, que es una biblioteca de animación de resorte en Facebook, establezca un valor objetivo y cambiará al valor objetivo según la tensión, la fricción y la velocidad actuales. La ecuación de aceleración es
donde la tensión es el coeficiente elástico y la fricción es el coeficiente de fricción. ¿Por qué la fricción debería ser proporcional a la velocidad? ¿Por qué la fricción debería ser proporcional a la velocidad? Si la fuerza de fricción es proporcional a la velocidad, entonces no hay fuerza de fricción estática, es decir, no existe una situación en la que la fuerza de tracción sea menor que la fuerza de fricción cuando el objeto está estacionario (porque cuando la velocidad es 0, la resistencia es 0, a menos que la fuerza de tracción sea 0), el objeto estará cerca de la posición objetivo, el objeto de contención tiene demasiada fricción para llegar al destino
Para facilitar el acceso a varias vistas, se creó una clase ZoomableGestureHelper está diseñado
Para fines de diseño, solo necesito conocer la vista Los límites de tamaño (límites) y los límites internos de rebote desplazables (innerBounds), luego puedo calcular una nueva matriz de transición
Para el estado físico, use una clase SpringPhysicsState para el almacenamiento, que contiene velocidad, coeficiente de estiramiento, coeficiente de fricción, pero la posición no se guarda porque la posición se calcula dinámicamente a través de getBounds
La velocidad se descompone en la dirección horizontal y la dirección vertical, debido a que el método de procesamiento es el mismo, solo la dirección vertical se describe a continuación Cálculo de la dirección
Estado 1: Un lado está fuera de límites
Analizar la posición en la imagen de arriba. La parte azul es la imagen interna. Fue arrastrada fuera de los límites. En este momento, la fuerza resultante debe ser fuerza de tracción * dx - Fuerza de fricción * v, v es la velocidad de la imagen. la dirección del eje y (dx y v son ambos vectores, estableceré la derecha y hacia abajo en positivo por ahora), luego llame a invalidate() directamente; la animación estará lista para reproducirse.
Estado 2: Ninguno de los lados está fuera de los límites.
En este punto, dado que ninguno de los lados está fuera de los límites, no debería haber fuerza de estiramiento y se puede asumir que dx es 0. . A lo que se debe prestar atención es a la fuerza de fricción, porque la fuerza de fricción puede soportarse mediante deslizamiento (Fling), por lo que la fuerza de fricción en este momento debe ser menor que la fuerza de fricción durante el último rebote transfronterizo. se dará al final del artículo. El valor específico se dará al final del artículo
Estado 3: ambos lados están más allá del límite
En este momento, ambos lados están más allá del límite y el área azul debe estar vinculado al centro del área roja, por lo que dx en este momento es dxBottom - dxTop (tenga en cuenta el símbolo, debido a que dx es un vector, no puede ser dxTop - dxBottom)
El método de escala es Lo mismo que el método de movimiento, establezca la tensión y la fricción y establezca el límite en Fuera del cuadro rojo, si el área azul no puede llenar el área roja en un lado, habrá fuerza de tracción; de lo contrario, no habrá fuerza de tracción. Y la fricción siempre existirá. En cuanto a hacer doble clic para acercar y alejar, solo necesita establecer la velocidad inicial en el estado de hacer doble clic para acercar y alejar, luego invalidar (); y listo. ! ¿No es muy simple?
El tiempo es un parámetro muy importante en el cálculo. Está relacionado con el cambio de valor numérico en el estado diferencial actual si utilizamos el método de Euler para simular el cambio de velocidad. posición, x'= x v*dt, v'=v a*dt Se puede ver en la fórmula que el tiempo determina la velocidad de reproducción de la animación. Para estar cerca del tiempo físico en la realidad, la unidad de tiempo utilizada aquí. son segundos (los milisegundos se usan comúnmente en las computadoras)
La unidad de tiempo de la animación son segundos y la unidad de tiempo son segundos.
Después de determinar la unidad, también necesitamos controlar el rango de valores del intervalo de tiempo. No podemos permitir que el intervalo de tiempo entre dos ComputScrolls sea demasiado corto o demasiado largo. La estrategia que adoptamos aquí es arreglar cada uno. cálculo El intervalo de tiempo entre dos ComputeScrolls Si el intervalo de tiempo entre dos ComputeScrolls es menor que este valor, se guardará el tiempo acumulado. Si el intervalo de tiempo entre dos ComputeScrolls es menor que este intervalo de tiempo, el tiempo acumulado se guardará y esperará. para el siguiente cálculo, desplácese hasta el intervalo de tiempo mayor o igual a un intervalo de tiempo fijo y luego use un bucle while para calcular paso a paso.
El juicio final es la única trampa, porque la computadora solo simula. los cambios en velocidad y desplazamiento dentro del tiempo dt, y no se somete a cálculos, por lo que hay errores, por ejemplo, en el método de Euler, x' = x v * dt y v ' = v a * dt son valores aproximados, y el los cambios dentro del tiempo dt se consideran un movimiento de velocidad uniforme
Por lo tanto, es necesario establecer un umbral para el juicio final. Cuando la velocidad y el desplazamiento son menores que este valor, se puede considerar que el destino ha sido alcanzado
Hay algunos problemas con la adaptación de ViewPager. Si está en la posición Abajo, es posible que necesite establecer una velocidad y un desplazamiento para el umbral del objeto en movimiento. requestDisallow true y requestDisallow false ViewPager mutará cuando se mueva hacia el límite izquierdo/derecho (las mutaciones son vergonzosas, pero útiles) y puede fallar al usar varios dedos, lo cual es un error en ViewPager. Por favor vea el código fuente