Как прокрутить до нижней части UITableView на iPhone, прежде чем появится представление - PullRequest
129 голосов
/ 05 мая 2010

У меня есть UITableView, который заполнен ячейками переменной высоты. Я бы хотел, чтобы таблица прокручивалась до самого дна, когда представление открывается.

В настоящее время у меня есть следующая функция

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[log count]-1 inSection:0];
[self.table scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];

log - изменяемый массив, содержащий объекты, составляющие содержимое каждой ячейки.

Приведенный выше код прекрасно работает в viewDidAppear, однако это имеет неприятный побочный эффект: отображение верхней части таблицы при первом появлении представления и последующее его перепрыгивание вниз. Я бы предпочел, чтобы table view можно было прокрутить вниз, прежде чем оно появится.

Я попробовал прокрутить в viewWillAppear и viewDidLoad, но в обоих случаях данные еще не были загружены в таблицу, и оба выдают исключение.

Любое руководство будет высоко ценится, даже если это всего лишь случай, чтобы сказать мне, что у меня есть все, что возможно.

Ответы [ 31 ]

146 голосов
/ 05 мая 2010

Я верю, что звонок [table setContentOffset:CGPointMake(0, CGFLOAT_MAX)] сделает то, что вы хотите.

120 голосов
/ 16 апреля 2013

Я думаю, что самый простой способ это:

if (self.messages.count > 0)
{
    [self.tableView 
        scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.messages.count-1 
        inSection:0] 
        atScrollPosition:UITableViewScrollPositionBottom animated:YES];
}

Swift 3 Версия:

if messages.count > 0 {
    userDefinedOptionsTableView.scrollToRow(at: IndexPath(item:messages.count-1, section: 0), at: .bottom, animated: true)
}
120 голосов
/ 21 сентября 2011

С ответ Иакова , это код:

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    if (self.messagesTableView.contentSize.height > self.messagesTableView.frame.size.height) 
    {
        CGPoint offset = CGPointMake(0, self.messagesTableView.contentSize.height - self.messagesTableView.frame.size.height);
        [self.messagesTableView setContentOffset:offset animated:YES];
    }
}
41 голосов
/ 14 марта 2013

Если вам нужно прокрутить до ТОЧНОГО конца содержимого, вы можете сделать это следующим образом:

- (void)scrollToBottom
{
    CGFloat yOffset = 0;

    if (self.tableView.contentSize.height > self.tableView.bounds.size.height) {
        yOffset = self.tableView.contentSize.height - self.tableView.bounds.size.height;
    }

    [self.tableView setContentOffset:CGPointMake(0, yOffset) animated:NO];
}
31 голосов
/ 31 января 2014

Я использую autolayout, и ни один из ответов не сработал для меня. Вот мое решение, которое, наконец, сработало:

@property (nonatomic, assign) BOOL shouldScrollToLastRow;


- (void)viewDidLoad {
    [super viewDidLoad];

    _shouldScrollToLastRow = YES;
}


- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    // Scroll table view to the last row
    if (_shouldScrollToLastRow)
    {
        _shouldScrollToLastRow = NO;
        [self.tableView setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
    }
}
23 голосов
/ 17 октября 2013

принятое решение @ JacobRelkin не работало для меня в iOS 7.0 с использованием Auto Layout.

У меня есть собственный подкласс UIViewController, и я добавил переменную экземпляра _tableView в качестве подпредставления для view. Я позиционировал _tableView, используя Auto Layout. Я пытался вызвать этот метод в конце viewDidLoad и даже в viewWillAppear:. Ни один не работал.

Итак, я добавил следующий метод в свой пользовательский подкласс UIViewController.

- (void)tableViewScrollToBottomAnimated:(BOOL)animated {
    NSInteger numberOfRows = [_tableView numberOfRowsInSection:0];
    if (numberOfRows) {
        [_tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:numberOfRows-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:animated];
    }
}

Вызов [self tableViewScrollToBottomAnimated:NO] в конце viewDidLoad работает. К сожалению, это также заставляет tableView:heightForRowAtIndexPath: вызываться три раза для каждой ячейки.

22 голосов
/ 28 марта 2016

Вот расширение, которое я реализовал в Swift 2.0. Эти функции должны вызываться после загрузки tableview:

import UIKit

extension UITableView {
    func setOffsetToBottom(animated: Bool) {
        self.setContentOffset(CGPointMake(0, self.contentSize.height - self.frame.size.height), animated: true)
    }

    func scrollToLastRow(animated: Bool) {
        if self.numberOfRowsInSection(0) > 0 {
            self.scrollToRowAtIndexPath(NSIndexPath(forRow: self.numberOfRowsInSection(0) - 1, inSection: 0), atScrollPosition: .Bottom, animated: animated)
        }
    }
}
15 голосов
/ 06 марта 2017

Подробнее

  • Xcode 8.3.2, swift 3.1
  • Xcode 10.2 (10E125), Swift 5

код

import UIKit

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

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

tableView.scrollToBottom(animated: true)

Полный образец

Не забудьте вставить код решения!

import UIKit

class ViewController: UIViewController {

    private weak var tableView: UITableView?
    private lazy var cellReuseIdentifier = "CellReuseIdentifier"

    override func viewDidLoad() {
        super.viewDidLoad()
        let tableView = UITableView(frame: view.frame)
        view.addSubview(tableView)
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellReuseIdentifier)
        self.tableView = tableView
        tableView.dataSource = self
        tableView.performBatchUpdates(nil) { [weak self] result in
            if result { self?.tableView?.scrollToBottom(animated: true) }
        }
    }
}

extension ViewController: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 100
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath )
        cell.textLabel?.text = "\(indexPath)"
        return cell
    }
}
12 голосов
/ 05 марта 2015

На самом деле "Swifter" способ сделать это в быстром:

var lastIndex = NSIndexPath(forRow: self.messages.count - 1, inSection: 0)
self.messageTableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)

работа Идеально для меня.

9 голосов
/ 09 ноября 2011

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

NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:0] - 1) inSection:0];
[[self tableView] scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];

не сработало, потому что выдало ошибку, когда высота стола была меньше, чем высота кадра. Обратите внимание, что в моей таблице только один раздел.

Решение, которое работало для меня, заключалось в реализации следующего кода в viewWillAppear:

- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// on the initial cell load scroll to the last row (ie the latest Note)
if (initialLoad==TRUE) {
    initialLoad=FALSE; 
    NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:0] - 1) inSection:0];
    [[self tableView] scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
        CGPoint offset = CGPointMake(0, (1000000.0));
        [self.tableView setContentOffset:offset animated:NO];
    }
}

BOOL ivar initialLoad установлен в TRUE в viewDidLoad.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...