#ios #objective-c #iphone #uiscrollview #uiscrollviewdelegate
#iOS #objective-c #iPhone #uiscrollview #uiscrollviewdelegate
Вопрос:
Есть ли способ узнать, достиг ли UIScrollView
вершины или дна? Возможно, в методе:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView
willDecelerate:(BOOL)decelerate
Ответ №1:
Реализуйте UIScrollViewDelegate
в своем классе, а затем добавьте это:
-(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
}
}
Надеюсь, это то, что вам нужно! В противном случае придется повозиться, добавив дополнительные условия к приведенному выше коду и NSLog значение scrollOffset.
Комментарии:
1. Если вы находитесь в
navigationController
, вы можете захотеть сделать что-то более похожее на это:scrollOffset <= (0 - self.navigationController.navigationBar.frame.size.height - 20)
и(scrollOffset scrollHeight) >= scrollContentSizeHeight
2. Проблема с этим заключается в отказе … все вызывается дважды, как только достигает вершины или дна. Есть ли решение для этого, помимо отключения отображения таблицы или коллекции?
3. @denikov вы нашли какое-либо решение для этого?
4. scrollOffset может быть <0, если ограничение scrollview top!= 0
Ответ №2:
Ну, contentInsets
также задействованы, когда вы пытаетесь определить, находится ли ScrollView вверху или внизу. Вас также могут заинтересовать случаи, когда ваш ScrollView находится выше верха и ниже низа. Вот код, который я использую для поиска верхней и нижней позиций:
Swift:
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
}
}
Objective-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
Комментарии:
1. Это хороший ответ, реализация scrollviewdidscroll плохо сказывается на производительности
2. Как мне это вызвать, если не используется scrollViewDidScroll?
3. Из-за причуд математики с плавающей запятой я получал «verticalOffsetForBottom» 1879.05xxx и мой contentOffset. y был 1879 годом, когда оказался внизу в Swift 3. Поэтому я сменил
return scrollViewBottomOffset
наreturn scrollViewBottomOffset.rounded()
4. Начиная с iOS 11
safeAreaInsets
, это также учитывается.scrollView.contentOffset.y scrollView.bounds.height - scrollView.safeAreaInsets.bottom
5. В iOS 11 и выше вам может потребоваться использовать
adjustedContentInset
вместоcontentInset
.
Ответ №3:
Если вам нужен код в swift:
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 amp;amp; scrollView.contentOffset.y < (scrollView.contentSize.height - scrollView.frame.size.height)){
//not top and not bottom
}
}
Ответ №4:
Простое и понятное расширение:
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
}
}
На GitHub:
Ответ №5:
Я точно понял, как это сделать:
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!
}
Ответ №6:
Сделайте это так (для 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
}
}
}
Комментарии:
1. Добро пожаловать в SO! При публикации кода в вашем ответе полезно объяснить, как ваш код решает проблему OP 🙂