it-swarm.com.de

Suchen Sie die Bildlaufrichtung in einer UIScrollView?

Ich habe ein UIScrollView, das nur horizontales Scrollen erlaubt, und ich möchte wissen, in welche Richtung (links, rechts) der Benutzer scrollt. Was ich getan habe, war, die UIScrollView zu unterordnen und die touchesMoved -Methode zu überschreiben:

- (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");

    }

}

Aber diese Methode wird manchmal überhaupt nicht aufgerufen, wenn ich mich bewege. Was denkst du?

175
Alex1987

Das Ermitteln der Richtung ist relativ einfach. Beachten Sie jedoch, dass sich die Richtung im Verlauf einer Geste mehrmals ändern kann. Wenn Sie beispielsweise eine Bildlaufansicht mit aktiviertem Paging haben und der Benutzer wischt, um zur nächsten Seite zu wechseln, kann die ursprüngliche Richtung nach rechts verlaufen. Wenn Sie jedoch den Bounce-Modus aktiviert haben, wird für kurze Zeit überhaupt keine Richtung angezeigt dann kurz nach links gehen.

Um die Richtung zu bestimmen, müssen Sie das UIScrollView scrollViewDidScroll delegieren. In diesem Beispiel habe ich eine Variable mit dem Namen lastContentOffset erstellt, mit der ich den aktuellen Inhaltsoffset mit dem vorherigen vergleichen kann. Wenn es größer ist, scrollt die scrollView nach rechts. Wenn es weniger ist, scrollt die scrollView nach links:

// 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.    
}

Ich benutze die folgende Aufzählung, um die Richtung zu definieren. Das Festlegen des ersten Werts auf ScrollDirectionNone hat den zusätzlichen Vorteil, dass diese Richtung beim Initialisieren von Variablen als Standard festgelegt wird:

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

... Ich möchte wissen, in welche Richtung (links, rechts) der Benutzer blättert.

Verwenden Sie in diesem Fall unter iOS 5 und höher UIScrollViewDelegate, um die Richtung der Schwenkbewegung des Benutzers zu bestimmen:

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

Mit scrollViewDidScroll: ist ein guter Weg, um die aktuelle Richtung zu finden.

Wenn Sie wissen möchten, in welche Richtung nach der Benutzer den Bildlauf beendet hat, verwenden Sie Folgendes:

@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
    }
}
57
Justin Tanner

Es ist nicht erforderlich, eine zusätzliche Variable hinzuzufügen, um dies zu verfolgen. Verwenden Sie einfach die UIScrollView -Eigenschaft des panGestureRecognizer wie folgt. Leider funktioniert dies nur, wenn die Geschwindigkeit nicht 0 ist:

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");
}

Sie können eine Kombination von x- und y-Komponenten verwenden, um nach oben, unten, links und rechts zu suchen.

49
rounak

Die Lösung

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

In iOS8 Swift Ich habe diese Methode verwendet:

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)

}

Ich habe eine dynamische Ansicht, die die Position ändert, wenn der Benutzer einen Bildlauf durchführt, sodass die Ansicht so aussieht, als wäre sie an derselben Stelle auf dem Bildschirm geblieben. Ich verfolge auch, wann der Benutzer nach oben oder unten geht.

Hier ist auch eine alternative Möglichkeit:

func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    if targetContentOffset.memory.y < scrollView.contentOffset.y {
        println("Going up!")
    } else {
        println("Going down!")
    }
}
14
Esqarrouth

Swift 4:

Für das horizontale Scrollen können Sie einfach Folgendes tun:

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

Für vertikale Bildlaufänderung .x mit .y

14

Das hat bei mir funktioniert (in Objective-C):

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView{

        NSString *direction = ([scrollView.panGestureRecognizer translationInView:scrollView.superview].y >0)[email protected]"up":@"down";
        NSLog(@"%@",direction);
    }
- (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");
    }
}
7
Oded Regev

Alternativ ist es möglich, den Schlüsselpfad "contentOffset" zu beobachten. Dies ist nützlich, wenn Sie den Stellvertreter der Bildlaufansicht nicht festlegen/ändern können.

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

Nachdem Sie den Beobachter hinzugefügt haben, können Sie jetzt:

- (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
    }
}

Denken Sie daran, den Beobachter bei Bedarf zu entfernen. z.B. Sie können den Beobachter in viewWillAppear hinzufügen und in viewWillDisappear entfernen

5
xu huanze

Hier ist meine Lösung für Verhalten wie in @followben, aber ohne Verlust mit langsamem Start (wenn dy 0 ist)

@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
                }
            }
        }
    }
}
4
Andrey Zhukov

In Swift:

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

Sie können dies auch in scrollViewDidScroll tun.

Ich bevorzuge es, basierend auf der Antwort von @ memmons zu filtern

In Ziel-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
    } 
}

Beim Testen in - (void)scrollViewDidScroll:(UIScrollView *)scrollView:

NSLog(@"lastContentOffset: --- %f,   scrollView.contentOffset.x : --- %f", self.lastContentOffset, scrollView.contentOffset.x);

img

self.lastContentOffset Ändert sich sehr schnell, die Wertlücke beträgt fast 0,5f.

Es ist nicht notwendig.

Und gelegentlich kann es sein, dass bei korrekter Handhabung die Orientierung verloren geht. (Implementierungsanweisungen werden manchmal übersprungen)

sowie :

- (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.
    }
   ....

In 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
    }
}
1
black_pearl

Ich habe einen Teil der Antwort überprüft und die Antwort von AnswerBot ausgearbeitet, indem ich alles in einen Drop in der Kategorie UIScrollView eingepackt habe. Das "lastContentOffset" wird stattdessen in der uiscrollview gespeichert und muss dann nur noch aufgerufen werden:

- (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
  }
}

Quellcode unter https://github.com/tehjord/UIScrollViewScrollingDirection

1
Bjergsen

Wenn Sie mit UIScrollView und UIPageControl arbeiten, ändert diese Methode auch die Seitenansicht von 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)
}

Vielen Dank an @Esq's Swift code.

0
charles.cc.hsu

Swift 2.2 Einfache Lösung welche Spuren einzelne und mehrere Richtungen ohne Verlust.

  // 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
  }
0
fatihyildizhan

Wenn Paging aktiviert ist, können Sie diesen Code verwenden.

- (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");
    }
}
0
Perry
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
NSLog(@"px %f py %f",velocity.x,velocity.y);}

Verwenden Sie diese delegierte Methode der Bildlaufansicht.

Wenn die Geschwindigkeitskoordinate + ve ist, wird die Ansicht nach unten und die Ansicht nach oben gescrollt. In ähnlicher Weise können der linke und der rechte Bildlauf mit der x-Koordinate ermittelt werden.

0
Nilesh Tupe

Ok, für mich funktioniert diese Implementierung wirklich gut:

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

    }
}

Dadurch wird textView ausgelöst und nach dem Ende des Ziehvorgangs geschlossen

0
user2021505

Kurz & Einfach wäre, überprüfen Sie einfach den Geschwindigkeitswert, wenn er größer als Null ist, dann scrollen Sie nach links oder rechts:

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
    }
}
0
iDilip

Codes erklärt sich wohl von selbst. CGFloat difference1 und difference2 werden in derselben privaten Schnittstelle deklariert. Gut, wenn contentSize gleich bleibt.

- (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;

       }
0
user2511630