UIScrollView прокрутить вниз программно


298

Как я могу сделать UIScrollViewпрокрутку вниз в моем коде? Или в более общем смысле, в любой точке подпредставления?

Ответы:


626

Вы можете использовать setContentOffset:animated:функцию UIScrollView для прокрутки к любой части представления содержимого. Вот некоторый код, который будет прокручиваться вниз, при условии, что ваш scrollView self.scrollView:

CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];

Надеюсь, это поможет!


25
Вы, вероятно, хотите выполнить следующее для прокрутки вниз, а не из вида прокрутки: CGPoint bottomOffset = CGPointMake (0, [self.scrollView contentSize] .height - self.scrollView.frame.size.height);
Grantland Chew

70
Вы не принимаете во внимание вставки. Я думаю, что вы должны предпочесть этот bottomOffset:CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
Мартин

1
это не работает в ландшафтном режиме! не полностью прокрутить до дна
Мо Фарханд

1
Он не будет работать должным образом, если contentSizeниже, чем bounds. Так должно быть так:scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)
Bartłomiej Semańczyk

1
Это обрабатывает нижнюю вставку и выходит за пределы 0:let bottomOffsetY = max(collectionView.contentSize.height - collectionView.bounds.height + collectionView.contentInset.bottom, 0)
Чувственный

136

Быстрая версия принятого ответа для легкого копирования копии:

let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height)
scrollView.setContentOffset(bottomOffset, animated: true)

3
bottomOffset должен быть разрешен, а не var в вашем примере.
Гоббс Тайг

правда, изменил это. SWIFT2 материал :)
Esqarrouth

9
вам нужно проверить, если scrollView.contentSize.height - scrollView.bounds.size.height> 0, иначе вы получите странные результаты
iluvatar_GR

2
Это решение не идеально, когда у вас есть новая панель навигации.
Стремительный Кролик

@Josh, все еще жду дня, когда ТАК узнает об этом
Александр Г

53

Самое простое решение:

[scrollview scrollRectToVisible:CGRectMake(scrollview.contentSize.width - 1,scrollview.contentSize.height - 1, 1, 1) animated:YES];

Спасибо. Я забыл, что изменил свой вид прокрутки на UITableView, и этот код работал и для UITableView, FYI.
LevinsonTechnologies

1
Почему бы просто: [scrollview scrollRectToVisible: CGRectMake (0, scrollview.contentSize.height, 1, 1) animated: YES];
Йоханнес

29

Просто улучшение существующего ответа.

CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.contentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];

Он также заботится о нижней вставке (если вы используете ее для настройки вида прокрутки, когда клавиатура видна)


Это должен быть правильный ответ ... а не другие, которые сломаются, если у них когда-нибудь появится клавиатура.
Бен Гильдия

20

Быстрая реализация:

extension UIScrollView {
   func scrollToBottom(animated: Bool) {
     if self.contentSize.height < self.bounds.size.height { return }
     let bottomOffset = CGPoint(x: 0, y: self.contentSize.height - self.bounds.size.height)
     self.setContentOffset(bottomOffset, animated: animated)
  }
}

используй это:

yourScrollview.scrollToBottom(animated: true)

19

Неверно задано смещение содержимого по высоте размера содержимого: оно прокручивает нижнюю часть содержимого до верхней части представления прокрутки и, таким образом, скрывается.

Правильное решение состоит в том, чтобы прокрутить нижнюю часть содержимого до нижней части представления прокрутки, например, так ( svэто UIScrollView):

CGSize csz = sv.contentSize;
CGSize bsz = sv.bounds.size;
if (sv.contentOffset.y + bsz.height > csz.height) {
    [sv setContentOffset:CGPointMake(sv.contentOffset.x, 
                                     csz.height - bsz.height) 
                animated:YES];
}

1
Не должно ли это быть if (sv.contentOffset.y + csz.height > bsz.height) {?
i_am_jorf

@jeffamaphone - Спасибо, что спросили. На самом деле на данный момент я даже не уверен, какой цели условие должно было служить! Это setContentOffset:команда, которая важна.
Мэтт

Я полагаю, чтобы избежать вызова setContentOffset, если он ничего не собирается делать?
i_am_jorf

@jeffamaphone - Раньше считалось, что после поворота устройства представление прокрутки может заканчиваться так, чтобы его нижнее содержимое находилось выше нижней части кадра (потому что если мы поворачиваем представление прокрутки, его смещение содержимого остается постоянным, но высота представления прокрутки может увеличиться из-за для авторазмера). Условие гласит: если это произойдет, поместите содержимое внизу внизу кадра. Но было глупо с моей стороны включить условие, когда я вставил код. Условием является правильно тестирование для того, что он испытывал к, хотя.
Мэтт

15

Решение Swift 2.2 с contentInsetучетом

let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)

Это должно быть в расширении

extension UIScrollView {

  func scrollToBottom() {
    let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height + contentInset.bottom)
    setContentOffset(bottomOffset, animated: true)
  }
}

Обратите внимание, что вы можете проверить, если bottomOffset.y > 0перед прокруткой


14

Что если contentSizeниже чемbounds ?

Для Свифта это:

scrollView.setContentOffset(CGPointMake(0, max(scrollView.contentSize.height - scrollView.bounds.size.height, 0) ), animated: true)

13

Пролистать наверх

- CGPoint topOffset = CGPointMake(0, 0);
- [scrollView setContentOffset:topOffset animated:YES];

Прокрутить до низа

- CGPoint bottomOffset = CGPointMake(0, scrollView.contentSize.height - self.scrollView.bounds.size.height);
 - [scrollView setContentOffset:bottomOffset animated:YES];

7

Я также нашел другой полезный способ сделать это в случае, если вы используете UITableview (который является подклассом UIScrollView):

[(UITableView *)self.view scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

К вашему сведению, это только возможность UITableView
OhadM

7

Использование setContentOffset:animated:функции UIScrollView для прокрутки вниз в Swift.

let bottomOffset : CGPoint = CGPointMake(0, scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)

5

Похоже, что все ответы здесь не приняли во внимание безопасную область. Начиная с iOS 11, в iPhone X появилась безопасная зона. Это может повлиять на scrollViewcontentInset .

Для iOS 11 и выше, чтобы правильно прокрутить до конца с включенным содержимым. Вы должны использовать adjustedContentInsetвместо contentInset. Проверьте этот код:

  • Swift:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.adjustedContentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
  • Objective-C
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.adjustedContentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
  • Быстрое расширение (это сохраняет оригинал contentOffset.x):
extension UIScrollView {
    func scrollsToBottom(animated: Bool) {
        let bottomOffset = CGPoint(x: contentOffset.x,
                                   y: contentSize.height - bounds.height + adjustedContentInset.bottom)
        setContentOffset(bottomOffset, animated: animated)
    }
}

Ссылки:


5

С (необязательно) footerViewи contentInset, решение:

CGPoint bottomOffset = CGPointMake(0, _tableView.contentSize.height - tableView.frame.size.height + _tableView.contentInset.bottom);
if (bottomOffset.y > 0) [_tableView setContentOffset: bottomOffset animated: YES];

4

Swift:

Вы можете использовать расширение как это:

extension UIScrollView {
    func scrollsToBottom(animated: Bool) {
        let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.size.height)
        setContentOffset(bottomOffset, animated: animated)
    }
}

Использование:

scrollView.scrollsToBottom(animated: true)

3

Валдыр, надеюсь, это тебе поможет

CGPoint bottomOffset = CGPointMake(0, [textView contentSize].height - textView.frame.size.height);

if (bottomOffset.y > 0)
 [textView setContentOffset: bottomOffset animated: YES];

2

Категория на помощь!

Добавьте это к общему заголовку утилиты где-нибудь:

@interface UIScrollView (ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated;
@end

А затем к этой реализации утилиты:

@implementation UIScrollView(ScrollToBottom)
- (void)scrollToBottomAnimated:(BOOL)animated
{
     CGPoint bottomOffset = CGPointMake(0, self.contentSize.height - self.bounds.size.height);
     [self setContentOffset:bottomOffset animated:animated];
}
@end

Затем реализуйте его, где хотите, например:

[[myWebView scrollView] scrollToBottomAnimated:YES];

Всегда, всегда, всегда, всегда используйте категории! Идеальный :)
Толстяк

2

Для горизонтального ScrollView

Если я вам нравлюсь, у вас есть Horizontal ScrollView и вы хотите прокрутить его до конца (в моем случае до самого правого), вам нужно изменить некоторые части принятого ответа:

Objective-C

CGPoint rightOffset = CGPointMake(self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, 0 );
[self.scrollView setContentOffset:rightOffset animated:YES];

стриж

let rightOffset: CGPoint = CGPoint(x: self.scrollView.contentSize.width - self.scrollView.bounds.size.width + self.scrollView.contentInset.right, y: 0)
self.scrollView.setContentOffset(rightOffset, animated: true)

2

Если вы как-то измените scrollView contentSize (например, добавьте что-то в stackView, которое находится внутри scrollView), вы должны вызватьscrollView.layoutIfNeeded() перед прокруткой, в противном случае он ничего не делает.

Пример:

scrollView.layoutIfNeeded()
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.size.height + scrollView.contentInset.bottom)
if(bottomOffset.y > 0) {
    scrollView.setContentOffset(bottomOffset, animated: true)
}

1

Хороший способ обеспечить видимость нижней части вашего контента - использовать формулу:

contentOffsetY = MIN(0, contentHeight - boundsHeight)

Это гарантирует, что нижний край вашего контента всегда находится у нижнего края представления или над ним. MIN(0, ...)Требуется потому , что UITableView(и , вероятно UIScrollView) обеспечивает , contentOffsetY >= 0когда пользователь пытается прокручивать заметно щелкать contentOffsetY = 0. Это выглядит довольно странно для пользователя.

Код для реализации этого:

UIScrollView scrollView = ...;
CGSize contentSize = scrollView.contentSize;
CGSize boundsSize = scrollView.bounds.size;
if (contentSize.height > boundsSize.height)
{
    CGPoint contentOffset = scrollView.contentOffset;
    contentOffset.y = contentSize.height - boundsSize.height;
    [scrollView setContentOffset:contentOffset animated:YES];
}


1

В то время как Mattрешение кажется мне правильным, необходимо учитывать также вкладку представления коллекции, если она была настроена.

Адаптированный код будет:

CGSize csz = sv.contentSize;
CGSize bsz = sv.bounds.size;
NSInteger bottomInset = sv.contentInset.bottom;
if (sv.contentOffset.y + bsz.height + bottomInset > csz.height) {
    [sv setContentOffset:CGPointMake(sv.contentOffset.x, 
                                     csz.height - bsz.height + bottomInset) 
                animated:YES];
}

1

В скором времени:

   if self.mainScroll.contentSize.height > self.mainScroll.bounds.size.height {
        let bottomOffset = CGPointMake(0, self.mainScroll.contentSize.height - self.mainScroll.bounds.size.height);
        self.mainScroll.setContentOffset(bottomOffset, animated: true)
    }

1

Решение прокрутить до последнего элемента таблицы.

Свифт 3:

if self.items.count > 0 {
        self.tableView.scrollToRow(at:  IndexPath.init(row: self.items.count - 1, section: 0), at: UITableViewScrollPosition.bottom, animated: true)
}

0

Не работает для меня, когда я пытался использовать его в UITableViewControllerна self.tableView (iOS 4.1), после добавленияfooterView . Он прокручивается за границы, показывая черный экран.

Альтернативное решение:

 CGFloat height = self.tableView.contentSize.height; 

 [self.tableView setTableFooterView: myFooterView];
 [self.tableView reloadData];

 CGFloat delta = self.tableView.contentSize.height - height;
 CGPoint offset = [self.tableView contentOffset];
 offset.y += delta;

 [self.tableView setContentOffset: offset animated: YES];

0
CGFloat yOffset = scrollView.contentOffset.y;

CGFloat height = scrollView.frame.size.height;

CGFloat contentHeight = scrollView.contentSize.height;

CGFloat distance = (contentHeight  - height) - yOffset;

if(distance < 0)
{
    return ;
}

CGPoint offset = scrollView.contentOffset;

offset.y += distance;

[scrollView setContentOffset:offset animated:YES];

0

Я обнаружил, что contentSizeэто на самом деле не отражает фактический размер текста, поэтому при попытке прокрутки вниз он будет немного отключен. Лучший способ для определения фактического размера контента на самом деле использовать в NSLayoutManager«S usedRectForTextContainer:метода:

UITextView *textView;
CGSize textSize = [textView.layoutManager usedRectForTextContainer:textView.textContainer].size;

Чтобы определить, сколько текста на самом деле отображается в UITextView, вы можете рассчитать его, вычтя вставки текстового контейнера из высоты рамки.

UITextView *textView;
UIEdgeInsets textInsets = textView.textContainerInset;
CGFloat textViewHeight = textView.frame.size.height - textInsets.top - textInsets.bottom;

Тогда становится легко прокручиваться:

// if you want scroll animation, use contentOffset
UITextView *textView;
textView.contentOffset = CGPointMake(textView.contentOffset.x, textSize - textViewHeight);

// if you don't want scroll animation
CGRect scrollBounds = textView.bounds;
scrollBounds.origin = CGPointMake(textView.contentOffset.x, textSize - textViewHeight);
textView.bounds = scrollBounds;

Некоторые цифры для справки о том, что разные размеры представляют для пустого UITextView.

textView.frame.size = (width=246, height=50)
textSize = (width=10, height=16.701999999999998)
textView.contentSize = (width=246, height=33)
textView.textContainerInset = (top=8, left=0, bottom=8, right=0)

0

Расширьте UIScrollView, чтобы добавить метод scrollToBottom:

extension UIScrollView {
    func scrollToBottom(animated:Bool) {
        let offset = self.contentSize.height - self.visibleSize.height
        if offset > self.contentOffset.y {
            self.setContentOffset(CGPoint(x: 0, y: offset), animated: animated)
        }
    }
}

Что это добавляет к существующим ответам?
седобородый

-1

Xamarin.iOS версия принятого ответа

var bottomOffset = new CGPoint (0,
     scrollView.ContentSize.Height - scrollView.Frame.Size.Height
     + scrollView.ContentInset.Bottom);

scrollView.SetContentOffset (bottomOffset, false);

-1

Версия Xamarin.iOS для UICollectionViewпринятого ответа для простоты копирования и вставки

var bottomOffset = new CGPoint (0, CollectionView.ContentSize.Height - CollectionView.Frame.Size.Height + CollectionView.ContentInset.Bottom);          
CollectionView.SetContentOffset (bottomOffset, false);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.