ios uiview uigesturerecognizer uiviewanimation uipangesturerecognizer

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]; } }