cocoa touch - Predecir el desplazamiento de reposo en un UIScrollView después de la desaceleración
cocoa-touch (3)
Me gustaría poder predecir el desplazamiento final en reposo dentro de un UIScrollView después de un gesto rápido. No necesita ser preciso en píxeles, pero lo suficientemente cerca como para que el usuario no perciba una diferencia (es decir, no se mueva excesivamente menos o más de lo que está acostumbrado).
Sé que alguien preguntará, entonces: ¿Por qué? Tengo un control de menú similar a una vista de tabla dentro de un UIScrollView. Me gustaría hacerlo de tal manera que el elemento del menú que se encuentra más arriba se muestre completamente y se coloque en la parte superior de UIScrollView. La función de paginación de UIScrollView no es exactamente lo que quiero, porque una película fuerte no supera los múltiplos de los límites de vista.
El manejo de eventos táctiles normales es bastante fácil. En touchesEnded:withEvent:
puedo desplazarme al elemento del menú completo más cercano. La parte difícil es la desaceleración.
Hay dos constantes para la tasa de desaceleración, UIScrollViewDecelerationRateNormal
y UIScrollViewDecelerationRateFast
. Sus valores son 0.998 y 0.990 en iPhone OS 3.0. He tratado de descifrar las matemáticas que Apple usa para ralentizar el movimiento, pero me estoy quedando sin nada.
Si puedo predecir con cierta precisión el desplazamiento final en reposo, entonces temprano durante la desaceleración puedo simplemente usar scrollRectToVisible:animated:
para moverse a un desplazamiento con un elemento de menú al ras de la parte superior de los límites de vista.
¿Alguna gente con inclinaciones matemáticas sabe lo que Apple podría estar haciendo durante la desaceleración? ¿Debo reunir un montón de números de eventos de desaceleración, graficarlos y dar con algo cercano?
Controle el targetContentOffset de UIScrollView en iOS 5
iOS5 UIScrollViewDelegate
tiene un nuevo método: scrollViewWillEndDragging:withVelocity:targetContentOffset:
Esto encaja perfectamente con lo que quieres hacer.
Este método no se invoca cuando el valor de la propiedad pagingEnabled de la vista de desplazamiento es SÍ. Su aplicación puede cambiar el valor del parámetro targetContentOffset para ajustar donde la vista de desplazamiento termina su animación de desplazamiento.
Solución alternativa para iOS4 y más bajo
Cambie la UIScrollView
de decelerationRate
de UIScrollViewDecelerationFast
a UIScrollViewDecelerationFast
y luego en scrollViewDidEndDecelerating
mueva a la "página" más cercana.
La rápida desaceleración hace que el paro / deslizamiento completo sea un poco más natural / menos desagradable.
No puedo comentar (creo que necesito 50 repeticiones), así que esta no es una respuesta completa, pero dados los valores de 0.998 y 0.990 para la desaceleración, mi instinto es que simplemente multiplican la velocidad actual por la tasa de desaceleración en cada cuadro.
Puede observar la velocidad de desplazamiento mientras el UIScrollView está desacelerando, y cuando la velocidad cae por debajo de cierto valor, seleccione el elemento del menú más cercano.
Es probable que desee implementar los métodos UIScrollViewDelegate
scrollViewDidEndDragging:willDecelerate:
y scrollViewDidScroll:
Cuando el usuario levante el dedo para finalizar un gesto de desplazamiento, se scrollViewDidEndDragging:willDecelerate:
Comience a monitorear los eventos scrollViewDidScroll:
y observe el delta entre la posición actual de UIScrollView
y su posición anterior, dividido por el delta de tiempo:
float velocity = (currentPosition - lastPosition) / (currentTime - lastTime);
Cuando la velocidad cae por debajo de un valor mínimo, llame a scrollRectToVisible:animated:
en el UIScrollView
.