iPhone - Wissen, ob ein UIScrollView oben oder unten erreicht hat


81

Gibt es eine Möglichkeit zu wissen, ob a UIScrollViewoben oben oder unten angekommen ist?

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
                  willDecelerate:(BOOL)decelerate

?

Vielen Dank.

Antworten:


196

Implementieren Sie das UIScrollViewDelegatein Ihrer Klasse und fügen Sie Folgendes hinzu:

-(void)scrollViewDidScroll: (UIScrollView*)scrollView
{
    float scrollViewHeight = scrollView.frame.size.height;
    float scrollContentSizeHeight = scrollView.contentSize.height;
    float scrollOffset = scrollView.contentOffset.y;

    if (scrollOffset == 0)
    {
        // then we are at the top
    }
    else if (scrollOffset + scrollViewHeight == scrollContentSizeHeight)
    {
        // then we are at the end
    }
}

Hoffe das ist was du suchst! Andernfalls basteln Sie, indem Sie dem obigen Code weitere Bedingungen hinzufügen und den Wert von scrollOffset mit NSLog versehen.


4
Wenn Sie in einem sind navigationController, möchten Sie vielleicht etwas Ähnliches tun: scrollOffset <= (0 - self.navigationController.navigationBar.frame.size.height - 20)und(scrollOffset + scrollHeight) >= scrollContentSizeHeight
Wayne

Das Problem dabei ist der Sprung ... alles wird zweimal aufgerufen, sobald es oben oder unten erreicht ist. Gibt es eine Lösung dafür, außer das Abspringen der Tabelle oder der Sammlungsansicht?
Denikov

@denikov hast du eine lösung dafür gefunden?
Priyal

80

Nun, contentInsetssind auch beteiligt, wenn Sie versuchen festzustellen, ob scrollView oben oder unten ist. Sie könnten auch an Fällen interessiert sein, in denen sich Ihre scrollView über und unter der Unterseite befindet. Hier ist der Code, mit dem ich die oberen und unteren Positionen finde:

Schnell:

extension UIScrollView {

    var isAtTop: Bool {
        return contentOffset.y <= verticalOffsetForTop
    }

    var isAtBottom: Bool {
        return contentOffset.y >= verticalOffsetForBottom
    }

    var verticalOffsetForTop: CGFloat {
        let topInset = contentInset.top
        return -topInset
    }

    var verticalOffsetForBottom: CGFloat {
        let scrollViewHeight = bounds.height
        let scrollContentSizeHeight = contentSize.height
        let bottomInset = contentInset.bottom
        let scrollViewBottomOffset = scrollContentSizeHeight + bottomInset - scrollViewHeight
        return scrollViewBottomOffset
    }

}

Ziel c:

@implementation UIScrollView (Additions)

- (BOOL)isAtTop {
    return (self.contentOffset.y <= [self verticalOffsetForTop]);
}

- (BOOL)isAtBottom {
    return (self.contentOffset.y >= [self verticalOffsetForBottom]);
}

- (CGFloat)verticalOffsetForTop {
    CGFloat topInset = self.contentInset.top;
    return -topInset;
}

- (CGFloat)verticalOffsetForBottom {
    CGFloat scrollViewHeight = self.bounds.size.height;
    CGFloat scrollContentSizeHeight = self.contentSize.height;
    CGFloat bottomInset = self.contentInset.bottom;
    CGFloat scrollViewBottomOffset = scrollContentSizeHeight + bottomInset - scrollViewHeight;
    return scrollViewBottomOffset;
}


@end

Dies ist die gute Antwort, die Implementierung von scrollviewdidscroll ist schlecht für Leistungen
Vassily

3
Wie rufe ich es auf, wenn ich scrollViewDidScroll nicht verwende?
Dave G

2
Aufgrund der Unbestimmtheiten der Gleitkomma-Mathematik erhielt ich ein "vertikaleOffsetForBottom" von 1879.05xxx und mein contentOffset.y war 1879, als ich in Swift 3 ganz unten war. Also wechselte return scrollViewBottomOffsetreturn scrollViewBottomOffset.rounded()
ich

1
Ab iOS 11 wird safeAreaInsetsauch berücksichtigt. scrollView.contentOffset.y + scrollView.bounds.height - scrollView.safeAreaInsets.bottom
InkGolem

34

Wenn Sie den Code schnell haben möchten:

override func scrollViewDidScroll(scrollView: UIScrollView) {

    if (scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height)) {
        //reach bottom
    }

    if (scrollView.contentOffset.y <= 0){
        //reach top
    }

    if (scrollView.contentOffset.y > 0 && scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)){
        //not top and not bottom
    }
}

10

Einfache und saubere Erweiterung:

import UIKit

extension UIScrollView {

    var scrolledToTop: Bool {
        let topEdge = 0 - contentInset.top
        return contentOffset.y <= topEdge
    }

    var scrolledToBottom: Bool {
        let bottomEdge = contentSize.height + contentInset.bottom - bounds.height
        return contentOffset.y >= bottomEdge
    }

}

Auf GitHub:

https://github.com/salutis/swift-scroll-view-edges


4

Ich habe genau herausgefunden, wie es geht:

CGFloat maxPosition = scrollView.contentInset.top + scrollView.contentSize.height + scrollView.contentInset.bottom - scrollView.bounds.size.height;
CGFloat currentPosition = scrollView.contentOffset.y + self.topLayoutGuide.length;

if (currentPosition == maxPosition) {
  // you're at the bottom!
}

0

Mach es so (für Swift 3):

class MyClass: UIScrollViewDelegate {

   func scrollViewDidScroll(_ scrollView: UIScrollView) {

        if (scrollView.contentOffset.y >= (scrollView.contentSize.height - scrollView.frame.size.height)) {
           //scrolled to top, do smth
        }


    }
}

Willkommen bei SO! Wenn Sie Code in Ihrer Antwort veröffentlichen, ist es hilfreich zu erklären, wie Ihr Code das OP-Problem löst :)
Joel
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.