UIScrollView прокручуйте програмування донизу


298

Як я можу зробити UIScrollViewпрокрутку донизу в межах свого коду? Або більш загальним способом, до будь-якої точки підгляду?

Відповіді:


626

Ви можете використовувати функцію UIScrollView setContentOffset:animated:для прокрутки до будь-якої частини перегляду вмісту. Ось код, який прокручується донизу, припускаючи, що ваш 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]. висота - self.scrollView.frame.size.height);
Grantland Chew

70
Ви не враховуєте вставки. Думаю, вам слід віддати перевагу цьому нижньому наказу: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, все ще чекаю дня, коли дізнається про це
Олександр G

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) анімований: ТАК];
Йоганнес

29

Просто доповнення до існуючої відповіді.

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

Він також дбає про нижню вставку (якщо ви використовуєте це для налаштування подання прокрутки, коли клавіатура видна)


Це має бути правильна відповідь ... не інші, які зламаються, якщо у них коли-небудь з’явиться клавіатура.
Бен Гільдія

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 - Раніше після обертання пристрою перегляд прокрутки міг закінчуватися його вмістом внизу вище ніж нижній частині кадру (тому що якщо ми обертаємо подання прокрутки, зміщення вмісту залишається постійним, але висота подання прокрутки, можливо, зросла через до автоматизації). Умова говорить: Якщо це трапиться, покладіть вміст знизу назад внизу кадру. Але мені було нерозумно включати умову, коли я вставляв у код. Умова така правильно тестування для того, що він відчував до, хоча.
мат

19

Швидка реалізація:

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)

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 ?

Для Swift це:

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];

FYI, це лише можливість
UITableView

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. Перевірте цей код:

  • Швидкий:
let bottomOffset = CGPoint(x: 0, y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.adjustedContentInset.bottom)
scrollView.setContentOffset(bottomOffset, animated: true)
  • Ціль-С
CGPoint bottomOffset = CGPointMake(0, self.scrollView.contentSize.height - self.scrollView.bounds.size.height + self.scrollView.adjustedContentInset.bottom);
[self.scrollView setContentOffset:bottomOffset animated:YES];
  • Розширення Swift (це зберігає оригінал 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

Швидкий:

Ви можете використовувати таке розширення:

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

valdyr, сподіваюся, що це допоможе тобі:

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];

Завжди, завжди, завжди, завжди використовуйте категорії! Ідеально :)
Fattie

2

Для горизонтального перегляду ScrollView

Якщо вам подобається, що у мене є горизонтальний ScrollView і ви хочете прокрутити його до кінця (у моєму випадку з правої частини), вам потрібно змінити деякі частини прийнятої відповіді:

Ціль-С

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.