Получить UIScrollView, чтобы прокрутить к вершине

Ответы:

316

ОБНОВЛЕНИЕ ДЛЯ iOS 7

[self.scrollView setContentOffset:
    CGPointMake(0, -self.scrollView.contentInset.top) animated:YES];

ОРИГИНАЛ

[self.scrollView setContentOffset:CGPointZero animated:YES];

или если вы хотите сохранить положение горизонтальной прокрутки и просто сбросить положение по вертикали:

[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, 0)
    animated:YES];
Роб Майофф
источник
50
Если вы делаете это для iOS 7, вам, возможно, придется принять во внимание UIScrollView contentInset, к сожалению. [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];делает работу для меня
runmad
11
Я смог прокрутить вверх, прямо под панелью навигации и состояния. [scrollView setContentOffset:CGPointMake(0, -scrollView.contentInset.top) animated:YES];Это работает в iOS 6 и 7
Amozoss
Это не сработало для меня, вероятно, потому что я делаю что-то сумасшедшее с перевернутым представлением в наборе спрайтов. Но если кто-то еще такой же сумасшедший, как и я - и ваш скролл-просмотр по умолчанию находится внизу - он прокрутит его до самого верха:[scrollView setContentOffset:CGPointMake(0, scrollView.contentSize.height-scrollView.frame.size.height) animated:YES];
GilesDMiddleton
Комментарий позднего дня: вы должны отрегулировать вставку содержимого независимо от версии ОС. В iOS 7 он используется для прокрутки контента под строкой состояния, но он всегда был представлен как свойство, поэтому всегда мог использоваться кем-то.
Томми
2
Для iOS 11+ ответ Якуба Трухларжа, приведенный ниже, с использованием AdjustContentInset был полезным, по крайней мере, в моем случае.
17
61

Вот расширение Swift, которое облегчает:

extension UIScrollView {
    func scrollToTop() {
        let desiredOffset = CGPoint(x: 0, y: -contentInset.top)
        setContentOffset(desiredOffset, animated: true)
   }
}

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

myScrollView.scrollToTop()
Эндрю Шрайбер
источник
40

iOS 11 и выше

попробуй поработай с новым adjustedContentInset.

Например (прокрутите вверх):

var offset = CGPoint(
    x: -scrollView.contentInset.left, 
    y: -scrollView.contentInset.top)

if #available(iOS 11.0, *) {
    offset = CGPoint(
        x: -scrollView.adjustedContentInset.left, 
        y: -scrollView.adjustedContentInset.top)    
}

scrollView.setContentOffset(offset, animated: true)

Даже если вы используете prefersLargeTitlesи safe areaт. Д.

Якуб Трухларж
источник
40

Для Swift 4

scrollView.setContentOffset(.zero, animated: true)
Раджасехар Пасупулети
источник
23

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

[scrollView setContentOffset:CGPointZero animated:YES];
Брайан Чен
источник
17

Ответ для Swift 2.0 / 3.0 / 4.0 и iOS 7+:

let desiredOffset = CGPoint(x: 0, y: -self.scrollView.contentInset.top)
self.scrollView.setContentOffset(desiredOffset, animated: true)
worthbak
источник
8

В iOS7 у меня были проблемы с получением определенного вида прокрутки для перехода наверх, который работал в iOS6, и использовал это, чтобы настроить вид прокрутки для перехода наверх.

[self.myScroller scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
hoak
источник
У меня такая же проблема в iOS7. Кто-нибудь знает, как включить это для UITableView?
DZenBot
1
Забавно, как это работает, когда анимация - НЕТ, но не когда анимация - ДА. Если ДА, то он прокручивается почти до topdevgm16
Мэтт Беккер
4

Версия Swift 3.0.1 от Rob Mayoff :

self.scrollView.setContentOffset(
CGPoint(x: 0,y: -self.scrollView.contentInset.top),
animated: true)
Рони Леш
источник
2

Чтобы полностью копировать поведение строки состояния scrollToTop, нам нужно не только установить contentOffset, но и убедиться, что отображаются scrollIndicators. В противном случае пользователь может быстро потеряться.

Единственный публичный способ сделать это flashScrollIndicators. К сожалению, вызов его один раз после установки contentOffset не имеет никакого эффекта, потому что он сбрасывается немедленно. Я обнаружил, что это работает, когда делает вспышку каждый раз в scrollViewDidScroll:.

// define arbitrary tag number in a global constants or in the .pch file
#define SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG 19291

- (void)scrollContentToTop {
    [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];

    self.scrollView.tag = SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.scrollView.tag = 0;
    });
}

В вашем UIScrollViewDelegate (или UITable / UICollectionViewDelegate) реализуйте это:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.tag == SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG) {
        [scrollView flashScrollIndicators];
    }
}

Задержка скрытия немного короче по сравнению с поведением scrollToTop в строке состояния, но все равно выглядит хорошо.

Обратите внимание, что я злоупотребляю тэгом представления для сообщения о состоянии «isScrollingToTop», потому что мне это нужно через контроллеры вида. Если вы используете теги для чего-то другого, вы можете заменить это на iVar или свойство.

Ортвин Генц
источник
Я не проверял, но он должен выдать это при следующем цикле выполнения, если вы просто используете DISPATCH_TIME_NOW. Спасибо за выполнение этой работы, не уверен, что она мне еще нужна, но полезно знать.
Дэн Розенстарк
Это было давно, и я точно не помню, но я верю, что это не сработало. Откладывание до следующего цикла выполнения обычно является первым, что я пробую в таких случаях.
Ортвин Генц
2

Я думаю, что у меня есть ответ, который должен быть полностью совместим с iOS 11, а также с предыдущими версиями (для вертикальной прокрутки)

При этом учитывается новое значение selectedContentInset, а также учитывается дополнительное смещение, необходимое при включении prefersLargeTitles на навигационной панели, которое, по-видимому, требует дополнительного смещения в 52 пикселя поверх значения по умолчанию.

Это было немного сложно, потому чтоsetContentInset изменяется в зависимости от состояния titleBar (большой заголовок против маленького заголовка), поэтому мне нужно было проверить и посмотреть, какова была высота titleBar, и не применять смещение 52px, если оно уже находится в большом состоянии. Не удалось найти какой-либо другой метод для проверки состояния navigationBar, поэтому, если у кого-то есть лучший вариант, чем видеть, является ли высота> 44,0, я бы хотел услышать его

func scrollToTop(_ scrollView: UIScrollView, animated: Bool = true) {
    if #available(iOS 11.0, *) {
        let expandedBar = (navigationController?.navigationBar.frame.height ?? 64.0 > 44.0)
        let largeTitles = (navigationController?.navigationBar.prefersLargeTitles) ?? false
        let offset: CGFloat = (largeTitles && !expandedBar) ? 52: 0
        scrollView.setContentOffset(CGPoint(x: 0, y: -(scrollView.adjustedContentInset.top + offset)), animated: animated)
    } else {
        scrollView.setContentOffset(CGPoint(x: 0, y: -scrollView.contentInset.top), animated: animated)
    }
}

Вдохновленный решением Якуба

user2898617
источник
2

Это очень распространено, когда ваша панель навигации перекрывает небольшую часть содержимого scrollView и выглядит так, будто контент начинается не сверху. Для исправления я сделал 2 вещи:

  • Инспектор размеров - Просмотр прокрутки - Вставки содержимого -> Изменить с автоматического на никогда.
  • Инспектор размеров - Ограничения - «Выровнять по верху» (Ограничения верхнего выравнивания) - Второй элемент -> Изменить с Superview.Top на Safe Area.Top, а значение (постоянное поле) установить равным 0

Содержание вставок - Никогда Совместите ScrolView.Top с Safe Area.Top

Витя Шурапов
источник
1

Прокрутка к началу для UITableViewController, UICollectionViewControllerили любого UIViewControllerимеющейUIScrollView

extension UIViewController {

  func scrollToTop(animated: Bool) {
    if let tv = self as? UITableViewController {
        tv.tableView.setContentOffset(CGPoint.zero, animated: animated)
    } else if let cv = self as? UICollectionViewController{
        cv.collectionView?.setContentOffset(CGPoint.zero, animated: animated)
    } else {
        for v in view.subviews {
            if let sv = v as? UIScrollView {
                sv.setContentOffset(CGPoint.zero, animated: animated)
            }
        }
    }
  }
}
Shoaib
источник
0

В SWIFT 5 Просто установите смещение контента на ноль

scrollView.setContentOffset(CGPoint.zero, animated: true)
Абдул Карим Хан
источник
-4

Я перепробовал все способы. Но у меня ничего не получалось. Наконец-то мне это понравилось.

Я добавил self.view .addSubview(self.scroll)строку кода в viewDidLoad. После начала настройки рамки для просмотра с прокруткой и добавления компонентов для просмотра с прокруткой.

Это сработало для меня.

Убедитесь, что вы добавили self.view .addSubview(self.scroll)строку в начале. Затем вы можете добавить элементы пользовательского интерфейса.

Нарасимха Налламсетти
источник
Пожалуйста, удалите это. Хотя это, безусловно, имело смысл в то время, проблемы иерархии вашего подпредставления не имеют отношения к этому вопросу.
Дэн Розенстарк
1
@Cristik, если ваше представление прокрутки не находится в иерархии представлений, или ваш компьютер выключен, конечно, все это не будет работать. Но ОП спросил что-то довольно узкое
Дэн Розенстарк