ios - Animación UIView basada en UIPanGestureRecognizer velocity
uigesturerecognizer uiviewanimation (3)
Me gustaría poder mover una subvista dentro y fuera de la pantalla, de forma similar a como navegas entre las imágenes en la versión de iPhone en la aplicación Fotos, así que si la subvista está a más de 1/2 de la pantalla cuando la dejo ir con el dedo, debe animar fuera de la pantalla, pero también debe admitir el deslizamiento, por lo que si la velocidad del deslizamiento / panorámica es lo suficientemente alta, debe animarse fuera de la pantalla aunque esté a menos de 1/2 de la pantalla.
Mi idea era usar UIPanGestureRecognizer y luego probar la velocidad. Esto funciona, pero ¿cómo configuro una duración correcta de la animación para mover UIView en función de la ubicación actual de la vista y la velocidad de la panorámica para que parezca uniforme? Si configuro un valor fijo, la animación comienza a ser lenta o rápida en comparación con la velocidad de deslizamiento de mis dedos.
En la mayoría de los casos, configurar la opción UIViewAnimationOptionBeginFromCurrentState
para UIView
animator es suficiente para realizar una animación continua sin problemas.
Los doctores dicen
La velocidad del gesto panorámico, que se expresa en puntos por segundo. La velocidad se divide en componentes horizontales y verticales.
Entonces, yo diría que, dado que desea mover su vista xPoints
(medida en pt) para dejarla fuera de la pantalla, podría calcular la duración de ese movimiento de la siguiente manera:
CGFloat xPoints = 320.0;
CGFloat velocityX = [panRecognizer velocityInView:aView].x;
NSTimeInterval duration = xPoints / velocityX;
CGPoint offScreenCenter = moveView.center;
offScreenCenter.x += xPoints;
[UIView animateWithDuration:duration animations:^{
moveView.center = offScreenCenter;
}];
Es posible que desee utilizar + (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
en + (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
lugar y probar diferentes UIViewAnimationOptions
.
Una observación sobre la UIPanGestureRecognizer
la velocidad en UIPanGestureRecognizer
: no conozco tu experiencia, pero encontré que la velocidad generada por el sistema en el simulador no es muy útil. (Está bien en el dispositivo, pero es problemático en el simulador).
Si se desplaza rápidamente y se detiene bruscamente, espera, y solo luego finaliza el gesto (por ejemplo, el usuario comienza a deslizar, se da cuenta de que esto no era lo que quería, se detienen y luego suelta el dedo), la velocidad informada por velocityInView:
en el estado UIGestureRecognizerStateEnded
cuando se liberó tu dedo parece ser la velocidad rápida antes de detener y esperar, mientras que la velocidad correcta en este ejemplo sería cero (o cerca de cero). En resumen, la velocidad indicada es la que estaba justo antes del final de la sartén, pero no la velocidad al final de la sartén.
Terminé calculando la velocidad yo mismo, de forma manual. (Parece una tontería que esto sea necesario, pero no vi ninguna forma de UIGestureRecognizerStateChanged
si realmente quería obtener la velocidad final de la sartén). En UIGestureRecognizerStateChanged
, cuando el estado es UIGestureRecognizerStateChanged
hago un seguimiento de la translationInView
actual y anteriorInView CGPoint, así como la hora, y luego usar esos valores cuando estaba en UIGestureRecognizerStateEnded
para calcular la velocidad final real. Funciona bastante bien
Aquí está mi código para calcular la velocidad. Resulta que no estoy usando la velocidad para calcular la velocidad de la animación, sino que la estoy usando para determinar si el usuario hizo una panorámica lo suficientemente rápida o la movió lo suficientemente rápido como para que la vista se moviera más allá de la mitad de la pantalla y así desencadenando la animación entre vistas, pero el concepto de calcular la velocidad final parece aplicable a esta pregunta. Aquí está el código:
- (void)handlePanGesture:(UIPanGestureRecognizer *)gesture
{
static CGPoint lastTranslate; // the last value
static CGPoint prevTranslate; // the value before that one
static NSTimeInterval lastTime;
static NSTimeInterval prevTime;
CGPoint translate = [gesture translationInView:self.view];
if (gesture.state == UIGestureRecognizerStateBegan)
{
lastTime = [NSDate timeIntervalSinceReferenceDate];
lastTranslate = translate;
prevTime = lastTime;
prevTranslate = lastTranslate;
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
prevTime = lastTime;
prevTranslate = lastTranslate;
lastTime = [NSDate timeIntervalSinceReferenceDate];
lastTranslate = translate;
[self moveSubviewsBy:translate];
}
else if (gesture.state == UIGestureRecognizerStateEnded)
{
CGPoint swipeVelocity = CGPointZero;
NSTimeInterval seconds = [NSDate timeIntervalSinceReferenceDate] - prevTime;
if (seconds)
{
swipeVelocity = CGPointMake((translate.x - prevTranslate.x) / seconds, (translate.y - prevTranslate.y) / seconds);
}
float inertiaSeconds = 1.0; // let''s calculate where that flick would take us this far in the future
CGPoint final = CGPointMake(translate.x + swipeVelocity.x * inertiaSeconds, translate.y + swipeVelocity.y * inertiaSeconds);
[self animateSubviewsUsing:final];
}
}