it-swarm.com.ru

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

Как сделать прокрутку UIScrollView наверх?

157
Jack

ОБНОВЛЕНИЕ ДЛЯ 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];
304
rob mayoff

Вот расширение Swift, которое упрощает:

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

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

myScrollView.scrollToTop()
51
Andrew Schreiber

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 и т.д.

30
Jakub Truhlář

Для Swift 4

scrollView.setContentOffset(.zero, animated: true)
25
Rajasekhar Pasupuleti

Используйте setContentOffset:animated:

[scrollView setContentOffset:CGPointZero animated:YES];
22
Bryan Chen

Ответ для 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)
16
worthbak

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

[self.myScroller scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
8
hoak

Swift 3.0.1 версия ответ Роба Мэйоффа :

self.scrollView.setContentOffset(
CGPoint(x: 0,y: -self.scrollView.contentInset.top),
animated: true)
4
Roni Leshes

Чтобы полностью копировать поведение строки состояния 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 или свойство.

2
Ortwin Gentz

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

Это учитывает новый fixedContentInset, а также учитывает дополнительное смещение, требуемое, когда 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)
    }
}

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

1
user2898617

Прокрутите вверх для 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)
            }
        }
    }
  }
}
1
Shoaib

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

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

Content insets - NeverAlign ScrolView.Top to Safe Area.Top

0
Vitya Shurapov