it-swarm.com.ru

Как прокрутить до конца UITableView на iPhone, прежде чем вид появится

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

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

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

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

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

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

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

124
acqu13sce

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

142
Jacob Relkin

От ответ Джейкоба , это код:

- (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];
    }
}
119
Osama F

Я думаю, что самый простой способ заключается в следующем:

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)
}
118
Chamira Fernando

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

- (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];
}
41
Hans One

Я использую 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)];
    }
}
31
RaffAl

принятое решение @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: вызывается три раза для каждой ячейки.

23
ma11hew28

Вот расширение, которое я реализовал в 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)
        }
    }
}
22
Ryan Herubin

Подробности

xCode 8.3.2, Swift 3.1

Код

import UIKit

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

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

tableView.scrollToBottom(animated: true)
14
Vasily Bodnarchuk

На самом деле «Swifter» способ сделать это в Swift:

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

идеально для меня.

12
XcodeNOOB

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

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.

9
T.J.

Для Свифта:

if tableView.contentSize.height > tableView.frame.size.height
        {
            let offset = CGPoint(x: 0, y: tableView.contentSize.height - tableView.frame.size.height)
            tableView.setContentOffset(offset, animated: false)
        }
8
Segev

Вместо этого вы должны использовать UITableViewScrollPositionBottom.

5
Erphan Rajput

Для Swift 3 (Xcode 8.1):

override func viewDidAppear(_ animated: Bool) {
    let numberOfSections = self.tableView.numberOfSections
    let numberOfRows = self.tableView.numberOfRows(inSection: numberOfSections-1)

    let indexPath = IndexPath(row: numberOfRows-1 , section: numberOfSections-1)
    self.tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.middle, animated: true)
}
5
Irshad Qureshi

Конечно, это ошибка . Возможно, где-то в вашем коде вы используете table.estimatedRowHeight = value (например, 100). Замените это значение на наибольшее значение, которое, по вашему мнению, может получить высота строки, , например, 500 .. Это должно решить проблему в сочетании со следующим кодом:

//auto scroll down example
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

dispatch_after(time, dispatch_get_main_queue(), {
    self.table.scrollToRowAtIndexPath(NSIndexPath(forRow: self.Messages.count - 1, inSection: 0), atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
})
4
Mohsen Karbassi

После долгих раздумий вот что сработало для меня:

var viewHasAppeared = false

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if !viewHasAppeared { goToBottom() }
}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    viewHasAppeared = true
}

private func goToBottom() {
    guard data.count > 0 else { return }
    let indexPath = NSIndexPath(forRow: data.count - 1, inSection: 0)
    tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: false)
    tableView.layoutIfNeeded()
}

Ключ оказался not wrapping scrollToRowAtIndexPath внутри dispatch_async, как некоторые предлагали, но просто следуя за ним с помощью вызова layoutIfNeeded.

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

(Также NB вам нужен флаг viewHasAppeared, потому что вы не хотите goToBottom каждый раз, когда вызывается viewDidLayoutSubviews. Он вызывается, например, всякий раз, когда меняется ориентация.)

3
skot

В Swift 3.0

self.tableViewFeeds.setContentOffset(CGPoint(x: 0, y: CGFLOAT_MAX), animated: true)
3
Amit Verma

Используя приведенные выше решения, вы прокрутите страницу до конца (только если содержимое таблицы загружается первым):

//Scroll to bottom of table
CGSize tableSize = myTableView.contentSize;
[myTableView setContentOffset:CGPointMake(0, tableSize.height)];
3
JimmyJammed

Спасибо Джейкобу за ответ. действительно полезно, если кому-то интересно с монотушем C # версии 

private void SetScrollPositionDown()
    {
        if (tblShoppingListItem.ContentSize.Height > tblShoppingListItem.Frame.Size.Height)
        {
            PointF offset = new PointF(0,
                                       tblShoppingListItem.ContentSize.Height -
                                       tblShoppingListItem.Frame.Size.Height);
            tblShoppingListItem.SetContentOffset(offset,true );
        }

    }
2
Mahesh

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

tableView.alpha = 0 // We want animation!
lastMessageShown = false // This is ivar

viewModel.fetch { [unowned self] result in
    self.tableView.reloadData()

    if !self.lastMessageShown {
        dispatch_async(dispatch_get_main_queue()) { [unowned self] in
            if self.rowCount > 0 {
                self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: self.rowCount, inSection: 0), atScrollPosition: .Bottom, animated: false)
            }

            UIView.animateWithDuration(0.1) {
                self.tableView.alpha = 1
                self.lastMessageShown = true // Do it once
            }
        }
    }
}
2
SoftDesigner

Функция вкл Swift 3 прокрутить вниз

 override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(false)
        //scroll down
        if lists.count > 2 {
            let numberOfSections = self.tableView.numberOfSections
            let numberOfRows = self.tableView.numberOfRows(inSection: numberOfSections-1)
            let indexPath = IndexPath(row: numberOfRows-1 , section: numberOfSections-1)
            self.tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.middle, animated: true)
        }
    }
2
Tarik
func scrollToBottom() {

    let sections = self.chatTableView.numberOfSections

    if sections > 0 {

        let rows = self.chatTableView.numberOfRows(inSection: sections - 1)

        let last = IndexPath(row: rows - 1, section: sections - 1)

        DispatchQueue.main.async {

            self.chatTableView.scrollToRow(at: last, at: .bottom, animated: false)
        }
    }
}

ты должен добавить 

DispatchQueue.main.async {
            self.chatTableView.scrollToRow(at: last, at: .bottom, animated: false)
        }

или он не будет прокручиваться до дна.

2
user515060

Используйте этот простой код для прокрутки нижней части tableView

NSInteger rows = [tableName numberOfRowsInSection:0];
            if(rows > 0) {

                [tableName scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:rows-1 inSection:0]
                                 atScrollPosition:UITableViewScrollPositionBottom
                                         animated:YES];
            }
2
Bibin Joseph

Если вы устанавливаете фрейм для просмотра таблицы программно, убедитесь, что вы устанавливаете фрейм правильно.

1
Narasimha Nallamsetty

В iOS это работало нормально для меня

CGFloat height = self.inputTableView.contentSize.height;
if (height > CGRectGetHeight(self.inputTableView.frame)) {
    height -= (CGRectGetHeight(self.inputTableView.frame) - CGRectGetHeight(self.navigationController.navigationBar.frame));
}
else {
    height = 0;
}
[self.inputTableView setContentOffset:CGPointMake(0, height) animated:animated];

Он должен быть вызван из viewDidLayoutSubviews

1
Josip B.

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

[YOURTABLEVIEWNAME setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
1
Anuj Kumar Rai

[self.tableViewInfo scrollRectToVisible: CGRectMake (0, self.tableViewInfo.contentSize.height-self.tableViewInfo.height, self.tableViewInfo.width, self.tableViewInfo.height) animated: YES];

1
leetvin

Принятый ответ не работал с моей таблицей (тысячи строк, динамическая загрузка), но код ниже работает:

- (void)scrollToBottom:(id)sender {
    if ([self.sections count] > 0) {
        NSInteger idx = [self.sections count] - 1;
        CGRect sectionRect = [self.tableView rectForSection:idx];
        sectionRect.size.height = self.tableView.frame.size.height;
        [self.tableView scrollRectToVisible:sectionRect animated:NO];
    }
}
1
user3246173

В Swift вам просто нужно

self.tableView.scrollToNearestSelectedRowAtScrollPosition(UITableViewScrollPosition.Bottom, animated: true)

чтобы сделать это автоматически прокрутите вниз

0
Even Cheng

В Swift 3.0 Если вы хотите перейти к какой-либо конкретной ячейке табличного представления, измените значение индекса ячейки, например, измените значение self.yourArr.count.

self.yourTable.reloadData()
self.scrollToBottom() 
func scrollToBottom(){
    DispatchQueue.global(qos: .background).async {
        let indexPath = IndexPath(row: self.yourArr.count-1, section: 0)
        self.tblComment.scrollToRow(at: indexPath, at: .bottom, animated: true)
    }
}
0
Amit Verma

Я считаю, что старые решения не работают с Swift3. 

Если вы знаете количество строк в таблице, вы можете использовать: 

tableView.scrollToRow(
    at: IndexPath(item: listCountInSection-1, section: sectionCount - 1 ), 
    at: .top, 
    animated: true)
0
ymutlu