¿Encontrar la dirección de desplazamiento en UIScrollView?

Tengo un UIScrollView con solo desplazamiento horizontal permitido, y me gustaría saber en qué dirección (izquierda, derecha) se desplaza el usuario. Lo que hice fue touchesMoved subclase de UIScrollView y anular el método touchesMoved :

 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [super touchesMoved:touches withEvent:event]; UITouch *touch = [touches anyObject]; float now = [touch locationInView:self].x; float before = [touch previousLocationInView:self].x; NSLog(@"%f %f", before, now); if (now > before){ right = NO; NSLog(@"LEFT"); } else{ right = YES; NSLog(@"RIGHT"); } } 

Pero este método a veces no se llama en absoluto cuando me muevo. ¿Qué piensas?

La determinación de la dirección es bastante sencilla, pero tenga en cuenta que la dirección puede cambiar varias veces en el transcurso de un gesto. Por ejemplo, si tiene una vista de desplazamiento con la búsqueda activada y el usuario desliza para ir a la página siguiente, la dirección inicial podría ser hacia la derecha, pero si tiene activado el rebote, irá brevemente en ninguna dirección y luego, brevemente ir hacia la izquierda.

Para determinar la dirección, deberá usar el delegado UIScrollView scrollViewDidScroll . En esta muestra, creé una variable llamada lastContentOffset que utilizo para comparar el offset de contenido actual con el anterior. Si es mayor, entonces scrollView se desplaza hacia la derecha. Si es menor, scrollView se desplaza hacia la izquierda:

 // somewhere in the private class extension @property (nonatomic, assign) CGFloat lastContentOffset; // somewhere in the class implementation - (void)scrollViewDidScroll:(UIScrollView *)scrollView { ScrollDirection scrollDirection; if (self.lastContentOffset > scrollView.contentOffset.x) { scrollDirection = ScrollDirectionRight; } else if (self.lastContentOffset < scrollView.contentOffset.x) { scrollDirection = ScrollDirectionLeft; } self.lastContentOffset = scrollView.contentOffset.x; // do whatever you need to with scrollDirection here. } 

Estoy usando la siguiente enumeración para definir la dirección. Establecer el primer valor en ScrollDirectionNone tiene el beneficio adicional de hacer que esa dirección sea la predeterminada al inicializar variables:

 typedef NS_ENUM(NSInteger, ScrollDirection) { ScrollDirectionNone, ScrollDirectionRight, ScrollDirectionLeft, ScrollDirectionUp, ScrollDirectionDown, ScrollDirectionCrazy, }; 

… Me gustaría saber en qué dirección (izquierda, derecha) se desplaza el usuario.

En ese caso, en iOS 5 y superior, use UIScrollViewDelegate para determinar la dirección del gesto panorámico del usuario:

 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x > 0) { // handle dragging to the right } else { // handle dragging to the left } } 

Usar scrollViewDidScroll: es una buena forma de encontrar la dirección actual.

Si desea saber la dirección una vez que el usuario ha terminado de desplazarse, use lo siguiente:

 @property (nonatomic) CGFloat lastContentOffset; - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { self.lastContentOffset = scrollView.contentOffset.x; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if (self.lastContentOffset < scrollView.contentOffset.x) { // moved right } else if (self.lastContentOffset > scrollView.contentOffset.x) { // moved left } else { // didn't move } } 

No es necesario agregar una variable adicional para realizar un seguimiento de esto. Simplemente use la propiedad panGestureRecognizer UIScrollView esta manera. Desafortunadamente, esto funciona solo si la velocidad no es 0:

 CGFloat yVelocity = [scrollView.panGestureRecognizer velocityInView:scrollView].y; if (yVelocity < 0) { NSLog(@"Up"); } else if (yVelocity > 0) { NSLog(@"Down"); } else { NSLog(@"Can't determine direction as velocity is 0"); } 

Puede usar una combinación de componentes xey para detectar arriba, abajo, izquierda y derecha.

La solución

 func scrollViewDidScroll(scrollView: UIScrollView) { if(scrollView.panGestureRecognizer.translationInView(scrollView.superview).y > 0) { print("up") } else { print("down") } } 

En iOS8 Swift, utilicé este método:

 override func scrollViewDidScroll(scrollView: UIScrollView){ var frame: CGRect = self.photoButton.frame var currentLocation = scrollView.contentOffset.y if frame.origin.y > currentLocation{ println("Going up!") }else if frame.origin.y < currentLocation{ println("Going down!") } frame.origin.y = scrollView.contentOffset.y + scrollHeight photoButton.frame = frame view.bringSubviewToFront(photoButton) } 

Tengo una vista dinámica que cambia de ubicación a medida que el usuario se desplaza, por lo que la vista puede parecer que permaneció en el mismo lugar en la pantalla. También estoy rastreando cuando el usuario sube o baja.

Aquí también hay una manera alternativa:

 func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { if targetContentOffset.memory.y < scrollView.contentOffset.y { println("Going up!") } else { println("Going down!") } } 
 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { CGPoint targetPoint = *targetContentOffset; CGPoint currentPoint = scrollView.contentOffset; if (targetPoint.y > currentPoint.y) { NSLog(@"up"); } else { NSLog(@"down"); } } 

Esto es lo que funcionó para mí (en Objective-C):

  - (void)scrollViewDidScroll:(UIScrollView *)scrollView{ NSString *direction = ([scrollView.panGestureRecognizer translationInView:scrollView.superview].y >0)?@"up":@"down"; NSLog(@"%@",direction); } 

Alternativamente, es posible observar la ruta clave “contentOffset”. Esto es útil cuando no es posible configurar / cambiar el delegado de la vista de desplazamiento.

 [yourScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil]; 

Después de agregar el observador, ahora puede:

 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ CGFloat newOffset = [[change objectForKey:@"new"] CGPointValue].y; CGFloat oldOffset = [[change objectForKey:@"old"] CGPointValue].y; CGFloat diff = newOffset - oldOffset; if (diff < 0 ) { //scrolling down // do something } } 

Recuerde quitar al observador cuando sea necesario. por ejemplo, podría agregar el observador en la vista MostrarAparecer y eliminarlo en la vistaDisparecerá

Aquí está mi solución para el comportamiento como en la respuesta @followben, pero sin pérdida con inicio lento (cuando dy es 0)

 @property (assign, nonatomic) BOOL isFinding; @property (assign, nonatomic) CGFloat previousOffset; - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { self.isFinding = YES; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (self.isFinding) { if (self.previousOffset == 0) { self.previousOffset = self.tableView.contentOffset.y; } else { CGFloat diff = self.tableView.contentOffset.y - self.previousOffset; if (diff != 0) { self.previousOffset = 0; self.isFinding = NO; if (diff > 0) { // moved up } else { // moved down } } } } } 

En rápido:

  func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { if scrollView.panGestureRecognizer.translation(in: scrollView).y < 0 { print("down") } else { print("up") } } 

Puedes hacerlo también en scrollViewDidScroll.

Swift 4:

Para el desplazamiento horizontal, simplemente puede hacer:

 if scrollView.panGestureRecognizer.translation(in: scrollView.superview).x > 0 { print("left") } else { print("right") } 

Para desplazamiento vertical, cambie .x con .y

Revisé algunas de las respuestas y elaboré la respuesta de AnswerBot envolviendo todo en una caída en la categoría UIScrollView. El “lastContentOffset” se guarda dentro del uiscrollview en su lugar y solo es cuestión de llamar:

 - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [scrollView setLastContentOffset:scrollView.contentOffset]; } - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { if (scrollView.scrollDirectionX == ScrollDirectionRight) { //Do something with your views etc } if (scrollView.scrollDirectionY == ScrollDirectionUp) { //Do something with your views etc } } 

Código fuente en https://github.com/tehjord/UIScrollViewScrollingDirection

Cuando la búsqueda está activada, puede usar estos códigos.

 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { self.lastPage = self.currentPage; CGFloat pageWidth = _mainScrollView.frame.size.width; self.currentPage = floor((_mainScrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1; if (self.lastPage < self.currentPage) { //go right NSLog(@"right"); }else if(self.lastPage > self.currentPage){ //go left NSLog(@"left"); }else if (self.lastPage == self.currentPage){ //same page NSLog(@"same page"); } } 

Códigos se explica a sí mismo, supongo. CGFloat difference1 y difference2 declarados en la misma interfaz privada de clase. Bueno si contentSize se mantiene igual.

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat contentOffSet = scrollView.contentOffset.y; CGFloat contentHeight = scrollView.contentSize.height; difference1 = contentHeight - contentOffSet; if (difference1 > difference2) { NSLog(@"Up"); }else{ NSLog(@"Down"); } difference2 = contentHeight - contentOffSet; } 

Ok, para mí esta implementación está funcionando realmente bien:

 @property (nonatomic, assign) CGPoint lastContentOffset; - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { _lastContentOffset.x = scrollView.contentOffset.x; _lastContentOffset.y = scrollView.contentOffset.y; } - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { if (_lastContentOffset.x < (int)scrollView.contentOffset.x) { // moved right NSLog(@"right"); } else if (_lastContentOffset.x > (int)scrollView.contentOffset.x) { // moved left NSLog(@"left"); }else if (_lastContentOffset.y<(int)scrollView.contentOffset.y){ NSLog(@"up"); }else if (_lastContentOffset.y>(int)scrollView.contentOffset.y){ NSLog(@"down"); [self.txtText resignFirstResponder]; } } 

Así que esto disparará textView para descartar después de que termine el arrastre

 - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { NSLog(@"px %f py %f",velocity.x,velocity.y);} 

Utilice este método delegado de scrollview.

Si y la coordenada de velocidad es + ve, la vista de desplazamiento se desplaza hacia abajo y si es -ve scrollview se desplaza hacia arriba. Del mismo modo, el desplazamiento hacia la izquierda y hacia la derecha se puede detectar utilizando la coordenada x.

Corto y Fácil, simplemente verifica el valor de velocidad, si es mayor que cero, entonces se desplaza hacia la izquierda, a la derecha:

 func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { var targetOffset = Float(targetContentOffset.memory.x) println("TargetOffset: \(targetOffset)") println(velocity) if velocity.x < 0 { scrollDirection = -1 //scrolling left } else { scrollDirection = 1 //scrolling right } } 

Si trabaja con UIScrollView y UIPageControl, este método también cambiará la vista de página de PageControl.

  func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer) { let targetOffset = targetContentOffset.memory.x let widthPerPage = scrollView.contentSize.width / CGFloat(pageControl.numberOfPages) let currentPage = targetOffset / widthPerPage pageControl.currentPage = Int(currentPage) } 

Gracias al código Swift de @Esq.

Swift 2.2 Solución simple que rastrea direcciones individuales y múltiples sin ninguna pérdida.

  // Keep last location with parameter var lastLocation:CGPoint = CGPointZero // We are using only this function so, we can // track each scroll without lose anyone override func scrollViewWillBeginDragging(scrollView: UIScrollView) { let currentLocation = scrollView.contentOffset // Add each direction string var directionList:[String] = [] if lastLocation.x < currentLocation.x { //print("right") directionList.append("Right") } else if lastLocation.x > currentLocation.x { //print("left") directionList.append("Left") } // there is no "else if" to track both vertical // and horizontal direction if lastLocation.y < currentLocation.y { //print("up") directionList.append("Up") } else if lastLocation.y > currentLocation.y { //print("down") directionList.append("Down") } // scrolled to single direction if directionList.count == 1 { print("scrolled to \(directionList[0]) direction.") } else if directionList.count > 0 { // scrolled to multiple direction print("scrolled to \(directionList[0])-\(directionList[1]) direction.") } // Update last location after check current otherwise, // values will be same lastLocation = scrollView.contentOffset }