J'ai un UIScrollView
avec seulement le défilement horizontal autorisé, et j'aimerais savoir dans quelle direction (gauche, droite) l'utilisateur fait défiler. Ce que j'ai fait a été de sous-classer le UIScrollView
et de remplacer la touchesMoved
méthode:
- (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");
}
}
Mais cette méthode n'est parfois pas du tout appelée lorsque je déménage. Qu'est-ce que tu penses?
iphone
ios
cocoa-touch
uiscrollview
Alex1987
la source
la source
Réponses:
La détermination de la direction est assez simple, mais gardez à l'esprit que la direction peut changer plusieurs fois au cours d'un geste. Par exemple, si vous avez une vue de défilement avec la pagination activée et que l'utilisateur glisse pour aller à la page suivante, la direction initiale peut être vers la droite, mais si vous avez activé le rebond, il n'ira brièvement dans aucune direction du tout et puis aller brièvement vers la gauche.
Pour déterminer la direction, vous devrez utiliser le
UIScrollView scrollViewDidScroll
délégué. Dans cet exemple, j'ai créé une variable nomméelastContentOffset
que j'utilise pour comparer le décalage de contenu actuel avec le précédent. S'il est supérieur, le scrollView défile vers la droite. S'il est inférieur, le scrollView défile vers la gauche:// 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. }
J'utilise l'énumération suivante pour définir la direction. La définition de la première valeur sur ScrollDirectionNone présente l'avantage supplémentaire de faire de cette direction la valeur par défaut lors de l'initialisation des variables:
typedef NS_ENUM(NSInteger, ScrollDirection) { ScrollDirectionNone, ScrollDirectionRight, ScrollDirectionLeft, ScrollDirectionUp, ScrollDirectionDown, ScrollDirectionCrazy, };
la source
lastContentOffset = scrollView.contentOffset.x;
lastContentOffset
type. Concernant la propriété vs les variables statiques: l'une ou l'autre des solutions est un bon choix. Je n'ai pas vraiment de préférence. C'est un bon point.Dans ce cas, sur iOS 5 et supérieur, utilisez le
UIScrollViewDelegate
pour déterminer la direction du mouvement panoramique de l'utilisateur:- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x > 0) { // handle dragging to the right } else { // handle dragging to the left } }
la source
L'utilisation
scrollViewDidScroll:
est un bon moyen de trouver la direction actuelle.Si vous souhaitez connaître la direction une fois que l'utilisateur a terminé le défilement, utilisez ce qui suit:
@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 } }
la source
Pas besoin d'ajouter une variable supplémentaire pour garder une trace de cela. Il suffit d' utiliser la
UIScrollView
de »panGestureRecognizer
propriété comme celui - ci. Malheureusement, cela ne fonctionne que si la vitesse n'est pas de 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"); }
Vous pouvez utiliser une combinaison de composants x et y pour détecter le haut, le bas, la gauche et la droite.
la source
La solution
func scrollViewDidScroll(scrollView: UIScrollView) { if(scrollView.panGestureRecognizer.translationInView(scrollView.superview).y > 0) { print("up") } else { print("down") } }
la source
velocityInView
au lieu detranslationInView
. Cela résout le problème qui se pose lors du changement de direction dans le même mouvement.Swift 4:
Pour le défilement horizontal, vous pouvez simplement faire:
if scrollView.panGestureRecognizer.translation(in: scrollView.superview).x > 0 { print("left") } else { print("right") }
Pour un changement de défilement vertical
.x
avec.y
la source
Dans iOS8 Swift, j'ai utilisé cette méthode:
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) }
J'ai une vue dynamique qui change d'emplacement au fur et à mesure que l'utilisateur fait défiler afin que la vue puisse sembler restée au même endroit sur l'écran. Je suis également le suivi lorsque l'utilisateur monte ou descend.
Voici également une alternative:
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { if targetContentOffset.memory.y < scrollView.contentOffset.y { println("Going up!") } else { println("Going down!") } }
la source
crollViewDidEndDecelerating
droit?Voici ce que cela a fonctionné pour moi (en Objective-C):
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ NSString *direction = ([scrollView.panGestureRecognizer translationInView:scrollView.superview].y >0)?@"up":@"down"; NSLog(@"%@",direction); }
la source
- (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"); } }
la source
En rapide:
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { if scrollView.panGestureRecognizer.translation(in: scrollView).y < 0 { print("down") } else { print("up") } }
Vous pouvez également le faire dans scrollViewDidScroll.
la source
Alternativement, il est possible d'observer le chemin de clé "contentOffset". Ceci est utile lorsqu'il n'est pas possible pour vous de définir / modifier le délégué de la vue de défilement.
[yourScrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
Après avoir ajouté l'observateur, vous pouvez maintenant:
- (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 } }
N'oubliez pas de retirer l'observateur si nécessaire. par exemple, vous pouvez ajouter l'observateur dans viewWillAppear et le supprimer dans viewWillDisappear
la source
Voici ma solution pour un comportement comme dans @followben answer, mais sans perte avec démarrage lent (quand dy vaut 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 } } } } }
la source
//Vertical detection
var lastVelocityYSign = 0 func scrollViewDidScroll(_ scrollView: UIScrollView) { let currentVelocityY = scrollView.panGestureRecognizer.velocity(in: scrollView.superview).y let currentVelocityYSign = Int(currentVelocityY).signum() if currentVelocityYSign != lastVelocityYSign && currentVelocityYSign != 0 { lastVelocityYSign = currentVelocityYSign } if lastVelocityYSign < 0 { print("SCROLLING DOWN") } else if lastVelocityYSign > 0 { print("SCOLLING UP") } }
Réponse de Mos6y https://medium.com/@Mos6yCanSwift/swift-ios-determine-scroll-direction-d48a2327a004
la source
J'ai vérifié une partie de la réponse et développé la réponse AnswerBot en enveloppant tout dans une goutte dans la catégorie UIScrollView. Le "lastContentOffset" est enregistré à la place dans uiscrollview, puis il suffit d'appeler:
- (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 } }
Code source sur https://github.com/tehjord/UIScrollViewScrollingDirection
la source
Je préfère faire du filtrage, basé sur la réponse de @ memmons
En Objective-C:
// in the private class extension @property (nonatomic, assign) CGFloat lastContentOffset; // in the class implementation - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (fabs(self.lastContentOffset - scrollView.contentOffset.x) > 20 ) { self.lastContentOffset = scrollView.contentOffset.x; } if (self.lastContentOffset > scrollView.contentOffset.x) { // Scroll Direction Left // do what you need to with scrollDirection here. } else { // omitted // if (self.lastContentOffset < scrollView.contentOffset.x) // do what you need to with scrollDirection here. // Scroll Direction Right } }
Lors d'un test dans
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
:NSLog(@"lastContentOffset: --- %f, scrollView.contentOffset.x : --- %f", self.lastContentOffset, scrollView.contentOffset.x);
self.lastContentOffset
change très rapidement, l'écart de valeur est de près de 0,5f.Ce n'est pas nécessaire.
Et parfois, lorsqu'il est manipulé dans des conditions précises, votre orientation peut se perdre. (instructions d'implémentation sautées parfois)
tel que :
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{ CGFloat viewWidth = scrollView.frame.size.width; self.lastContentOffset = scrollView.contentOffset.x; // Bad example , needs value filtering NSInteger page = scrollView.contentOffset.x / viewWidth; if (page == self.images.count + 1 && self.lastContentOffset < scrollView.contentOffset.x ){ // Scroll Direction Right // do what you need to with scrollDirection here. } ....
Dans Swift 4:
var lastContentOffset: CGFloat = 0 func scrollViewDidScroll(_ scrollView: UIScrollView) { if (abs(lastContentOffset - scrollView.contentOffset.x) > 20 ) { lastContentOffset = scrollView.contentOffset.x; } if (lastContentOffset > scrollView.contentOffset.x) { // Scroll Direction Left // do what you need to with scrollDirection here. } else { // omitted // if (self.lastContentOffset < scrollView.contentOffset.x) // do what you need to with scrollDirection here. // Scroll Direction Right } }
la source
Lorsque la pagination est activée, vous pouvez utiliser ce code.
- (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"); } }
la source
Codes s'explique, je suppose. CGFloat difference1 et difference2 déclarées dans la même interface privée de classe. Bon si contentSize reste le même.
- (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; }
la source
Ok donc pour moi cette implémentation fonctionne vraiment 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]; } }
Donc, cela déclenchera textView pour le rejeter après la fin du glissement
la source
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { NSLog(@"px %f py %f",velocity.x,velocity.y);}
Utilisez cette méthode déléguée de scrollview.
Si la coordonnée y de la vitesse est + ve, la vue de défilement défile vers le bas et si elle est de -ve, la vue de défilement défile vers le haut. De même, le défilement gauche et droit peut être détecté en utilisant la coordonnée x.
la source
Short & Easy serait, il suffit de vérifier la valeur de la vitesse, si elle est supérieure à zéro, alors son défilement à gauche ou à droite:
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { var targetOffset = Float(targetContentOffset.memory.x) println("TargetOffset: \(targetOffset)") println(velocity) if velocity.x < 0 { scrollDirection = -1 //scrolling left } else { scrollDirection = 1 //scrolling right } }
la source
Si vous travaillez avec UIScrollView et UIPageControl, cette méthode modifiera également la vue de page du PageControl.
func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { let targetOffset = targetContentOffset.memory.x let widthPerPage = scrollView.contentSize.width / CGFloat(pageControl.numberOfPages) let currentPage = targetOffset / widthPerPage pageControl.currentPage = Int(currentPage) }
Merci le code Swift de @Esq.
la source
Swift 2.2 Solution simple qui suit des directions simples et multiples sans aucune perte.
// 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 }
la source
Dans toutes les réponses supérieures, deux façons principales de résoudre le problème consistent à utiliser
panGestureRecognizer
oucontentOffset
. Les deux méthodes ont leurs inconvénients et leurs avantages.Méthode 1: panGestureRecognizer
Lorsque vous utilisez
panGestureRecognizer
comme ce que @followben a suggéré, si vous ne voulez pas faire défiler votre vue de défilement par programme, cela fonctionne correctement.- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { if ([scrollView.panGestureRecognizer translationInView:scrollView.superview].x > 0) { // handle dragging to the right } else { // handle dragging to the left } }
Les inconvénients
Mais si vous déplacez la vue de défilement avec le code suivant, le code supérieur ne peut pas le reconnaître:
setContentOffset(CGPoint(x: 100, y: 0), animation: false)
Méthode 2: contentOffset
var lastContentOffset: CGPoint = CGPoint.zero func scrollViewDidScroll(_ scrollView: UIScrollView) { if (self.lastContentOffset.x > scrollView.contentOffset.x) { // scroll to right } else if self.lastContentOffset.x < scrollView.contentOffset.x { // scroll to left } self.lastContentOffset = self.scrollView.contentOffset }
Les inconvénients
Si vous voulez changer contentOffset par programme, pendant le défilement (comme lorsque vous voulez créer un défilement infini), cette méthode pose problème, car vous pouvez changer
contentOffset
lors du changement de lieux d'affichage du contenu et dans ce temps, le code supérieur saute dans lequel vous faites défiler vers la droite ou la gauche.la source