inside doesn iphone uiscrollview

iphone - doesn - uiscrollview autolayout



Cómo detectar cuando un UIScrollView ha terminado de desplazarse (15)

UIScrollViewDelegate tiene dos métodos de delegado scrollViewDidScroll: y scrollViewDidEndScrollingAnimation: pero ninguno de estos le indica cuándo se completó el desplazamiento. scrollViewDidScroll solo le notifica que la vista de desplazamiento no se scrollViewDidScroll porque ya no se ha desplazado.

El otro método scrollViewDidEndScrollingAnimation solo parece scrollViewDidEndScrollingAnimation si desplaza la vista de desplazamiento por programación, no si el usuario se desplaza.

¿Alguien sabe de esquema para detectar cuando una vista de desplazamiento ha completado el desplazamiento?


Creo que scrollViewDidEndDecelerating es lo que quieres. Su método opcional UIScrollViewDelegates:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

Le dice al delegado que la vista de desplazamiento ha terminado decelerar el movimiento de desplazamiento.

Documentación UIScrollViewDelegate


Intenté la respuesta de Ashley Smart y funcionó a las mil maravillas. Aquí hay otra idea, con el uso de scrollViewDidScroll

-(void)scrollViewDidScroll:(UIScrollView *)sender { if(self.scrollView_Result.contentOffset.x == self.scrollView_Result.frame.size.width) { // You have reached page 1 } }

Solo tenía dos páginas, así que funcionó para mí. Sin embargo, si tiene más de una página, podría ser problemático (podría verificar si la compensación actual es un múltiplo del ancho, pero entonces no sabría si el usuario se detuvo en la 2ª página o está en camino hacia la 3ª o Más)


Los métodos que está buscando son scrollViewDidEndDragging:willDecelerate: y scrollViewDidEndDecelerating: El primero siempre se llama después de que el usuario levanta su dedo. Si se desplazan lo suficientemente rápido como para dar como resultado la desaceleración, desacelerará será YES y se llamará al segundo método una vez que se complete la desaceleración.

( Desde los documentos UIScrollViewDelegate )


Para recapitular (y para principiantes). No es tan doloroso Simplemente agregue el protocolo y luego agregue las funciones que necesita para la detección.

En la vista (clase) que contiene el UIScrolView, agregue el protocolo y luego agregue las funciones desde aquí a su vista (clase).

// -------------------------------- // In the "h" file: // -------------------------------- @interface myViewClass : UIViewController <UIScrollViewDelegate> // <-- Adding the protocol here // Scroll view @property (nonatomic, retain) UIScrollView *myScrollView; @property (nonatomic, assign) BOOL isScrolling; // Protocol functions - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView; // -------------------------------- // In the "m" file: // -------------------------------- @implementation BlockerViewController - (void)viewDidLoad { CGRect scrollRect = self.view.frame; // Same size as this view self.myScrollView = [[UIScrollView alloc] initWithFrame:scrollRect]; self.myScrollView.delegate = self; self.myScrollView.contentSize = CGSizeMake(scrollRect.size.width, scrollRect.size.height); self.myScrollView.contentInset = UIEdgeInsetsMake(0.0,22.0,0.0,22.0); // Allow dragging button to display outside the boundaries self.myScrollView.clipsToBounds = NO; // Prevent buttons from activating scroller: self.myScrollView.canCancelContentTouches = NO; self.myScrollView.delaysContentTouches = NO; [self.myScrollView setBackgroundColor:[UIColor darkGrayColor]]; [self.view addSubview:self.myScrollView]; // Add stuff to scrollview UIImage *myImage = [UIImage imageNamed:@"foo.png"]; [self.myScrollView addSubview:myImage]; } // Protocol functions - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { NSLog(@"start drag"); _isScrolling = YES; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { NSLog(@"end decel"); _isScrolling = NO; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { NSLog(@"end dragging"); if (!decelerate) { _isScrolling = NO; } } // All of the available functions are here: // https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIScrollViewDelegate_Protocol/Reference/UIScrollViewDelegate.html


Esto se ha descrito en algunas de las otras respuestas, pero aquí está (en el código) cómo combinar scrollViewDidEndDecelerating y scrollViewDidEndDragging:willDecelerate para realizar alguna operación cuando el desplazamiento haya finalizado:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [self stoppedScrolling]; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (!decelerate) { [self stoppedScrolling]; } } - (void)stoppedScrolling { // done, do whatever }


Tuve un caso de tocar y arrastrar acciones y descubrí que el arrastre llamaba a scrollViewDidEndDecelerating

Y el cambio se compensa manualmente con el código ([_scrollView setContentOffset: contentOffset animated: YES];) estaba llamando a scrollViewDidEndScrollingAnimation.

//This delegate method is called when the dragging scrolling happens, but no when the tapping - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { //do whatever you want to happen when the scroll is done } //This delegate method is called when the tapping scrolling happens, but no when the dragging -(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { //do whatever you want to happen when the scroll is done }


Para todos los rollos relacionados con las interacciones de arrastre, esto será suficiente:

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { _isScrolling = NO; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (!decelerate) { _isScrolling = NO; } }

Ahora, si su desplazamiento se debe a un programático setContentOffset / scrollRectVisible (con animated = YES o, obviamente, usted sabe cuando el desplazamiento se terminó):

- (void)scrollViewDidEndScrollingAnimation { _isScrolling = NO; }

Si su desplazamiento se debe a algo más (como la apertura del teclado o el cierre del teclado), parece que tendrá que detectar el evento con un hack porque scrollViewDidEndScrollingAnimation tampoco es útil.

El caso de una vista de desplazamiento PAGINADA :

Porque, supongo, Apple aplica una curva de aceleración, se llama a scrollViewDidEndDecelerating para cada arrastre, por lo que no es necesario usar scrollViewDidEndDragging en este caso.


Versión rápida de la respuesta aceptada:

func scrollViewDidScroll(scrollView: UIScrollView) { // example code } func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) { // example code } func scrollViewDidEndZooming(scrollView: UIScrollView, withView view: UIView!, atScale scale: CGFloat) { // example code }


UIScrollview tiene un método delegado

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

Agregue las siguientes líneas de código en el método de delegado

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { CGSize scrollview_content=scrollView.contentSize; CGPoint scrollview_offset=scrollView.contentOffset; CGFloat size=scrollview_content.width; CGFloat x=scrollview_offset.x; if ((size-self.view.frame.size.width)==x) { //You have reached last page } }


Si alguien necesita, aquí está la respuesta de Ashley Smart en Swift

func scrollViewDidScroll(_ scrollView: UIScrollView) { NSObject.cancelPreviousPerformRequests(withTarget: self) perform(#selector(UIScrollViewDelegate.scrollViewDidEndScrollingAnimation), with: nil, afterDelay: 0.3) ... } func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { NSObject.cancelPreviousPerformRequests(withTarget: self) ... }


Existe un método de UIScrollViewDelegate que se puede usar para detectar (o mejor dicho, ''predecir'') cuando el desplazamiento realmente ha terminado:

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>)

de UIScrollViewDelegate que se puede usar para detectar (o mejor decir ''predecir'') cuando el desplazamiento realmente ha terminado.

En mi caso lo usé con desplazamiento horizontal como sigue (en Swift 3 ):

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { perform(#selector(self.actionOnFinishedScrolling), with: nil, afterDelay: Double(velocity.x)) } func actionOnFinishedScrolling() { print("scrolling is finished") // do what you need }


Acaba de desarrollar una solución para detectar cuándo el desplazamiento finalizó en toda la aplicación: https://gist.github.com/k06a/731654e3168277fb1fd0e64abc7d899e

Se basa en la idea de rastrear cambios en los modos runloop. Y realice bloques al menos después de 0.2 segundos después de desplazarse.

Esta es la idea central para rastrear los cambios en los modos runloop iOS10 +:

- (void)tick { [[NSRunLoop mainRunLoop] performInModes:@[ UITrackingRunLoopMode ] block:^{ [self tock]; }]; } - (void)tock { self.runLoopModeWasUITrackingAgain = YES; [[NSRunLoop mainRunLoop] performInModes:@[ NSDefaultRunLoopMode ] block:^{ [self tick]; }]; }

Y solución para objetivos de baja implementación como iOS2 +:

- (void)tick { [[NSRunLoop mainRunLoop] performSelector:@selector(tock) target:self argument:nil order:0 modes:@[ UITrackingRunLoopMode ]]; } - (void)tock { self.runLoopModeWasUITrackingAgain = YES; [[NSRunLoop mainRunLoop] performSelector:@selector(tick) target:self argument:nil order:0 modes:@[ NSDefaultRunLoopMode ]]; }


Acabo de encontrar esta pregunta, que es más o menos lo mismo que pregunté: ¿cómo saber exactamente cuándo se ha detenido el desplazamiento de UIScrollView?

Aunque didEndDecelerating funciona cuando se desplaza, el panning con liberación estacionaria no se registra.

Finalmente encontré una solución. didEndDragging tiene un parámetro WillDecelerate, que es falso en la situación de liberación estacionaria.

Al verificar la desaceleración en DidEndDragging, combinado con didEndDecelerating, se obtienen las dos situaciones que son el final del desplazamiento.


Las 320 implementaciones son mucho mejores, aquí hay un parche para obtener un inicio / finalización consistente del desplazamiento.

-(void)scrollViewDidScroll:(UIScrollView *)sender { [NSObject cancelPreviousPerformRequestsWithTarget:self]; //ensure that the end of scroll is fired. [self performSelector:@selector(scrollViewDidEndScrollingAnimation:) withObject:sender afterDelay:0.3]; ... } -(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView { [NSObject cancelPreviousPerformRequestsWithTarget:self]; ... }


Una alternativa sería usar scrollViewWillEndDragging:withVelocity:targetContentOffset que se scrollViewWillEndDragging:withVelocity:targetContentOffset cada vez que el usuario levanta el dedo y contiene el desplazamiento del contenido del objetivo donde se detendrá el desplazamiento. Usar este desplazamiento de contenido en scrollViewDidScroll: identifica correctamente cuando la vista de desplazamiento ha dejado de desplazarse.

private var targetY: CGFloat? public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { targetY = targetContentOffset.pointee.y } public func scrollViewDidScroll(_ scrollView: UIScrollView) { if (scrollView.contentOffset.y == targetY) { print("finished scrolling") }