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.

Ente
quelle

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.

Luke
quelle
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
Alexander Dvornikov
quelle
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
    }
}
Ytbryan
quelle
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

Rudolf Adamkovič
quelle
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!
}
JPN
quelle
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
        }


    }
}
Radu Ghitescu
quelle
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