У меня UITableView
есть ячейка, заполненная ячейками переменной высоты. Я хотел бы, чтобы таблица прокручивалась вниз, когда представление отображается в поле зрения.
В настоящее время у меня есть следующая функция
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[log count]-1 inSection:0];
[self.table scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
log - это изменяемый массив, содержащий объекты, составляющие содержимое каждой ячейки.
Приведенный выше код работает нормально, viewDidAppear
однако имеет неприятный побочный эффект: при первом появлении представления верхняя часть таблицы отображается с последующим переходом вниз. Я бы предпочел, чтобы table view
можно было прокрутить вниз до его появления.
Я попробовал свиток viewWillAppear
и , viewDidLoad
но в обоих случаях данные не были загружены в таблицу еще и как исключение.
Любое руководство будет очень признательно, даже если это всего лишь случай сказать мне, что у меня есть все, что возможно.
источник
[table reloadData];
CGPoint(x: 0, y: tableView.contentSize.height)
?Думаю, самый простой способ:
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) }
источник
messages.count
уже реализованныйmyTableView.dataSource!.tableView(myTableView, numberOfRowsInSection: 0)
. Да, он длиннее, но может избежать повторения кода. Вам также необходимо обработать необязательноеdataSource
(не разворачивать принудительно, как в этом примере).Из ответа Джейкоба это код:
- (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]; } }
источник
UIEdgeInsetsInsetRect(self.messagesTableView.frame, self.messagesTableView.safeAreaInsets).height
Если вам нужно прокрутить до ТОЧНОГО конца содержимого, вы можете сделать это следующим образом:
- (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]; }
источник
yOffset = self.tableView.contentSize.height - self.tableView.bounds.size.height;
? Спасибо.self.tableView.contentSize.height
содержимого, представление таблицы может быть не видно, потому что вы прокручиваете содержимое ниже. Поэтому вам нужно прокрутить до одного «видимого промежутка в табличном представлении» над концом табличного представления.Я использую автопрокладку, и ни один из ответов у меня не помог. Вот мое решение, которое наконец сработало:
@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)]; } }
источник
setContentOffset
в какой-то другой момент, когда данные были извлечены и просмотр таблицы перезагружен?CGFLOAT_MAX
я использовалcontentSize.height - frame.height + contentInset.bottom
при установке начального смещения содержимого. ИспользованиеCGFLOAT_MAX
казалось испортить для меня.Принятое решение по @JacobRelkin не работает для меня в прошивкой 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:
три раза вызов каждой ячейки.источник
Вот расширение, которое я реализовал в 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) } } }
источник
На самом деле "Swifter" способ сделать это быстро:
var lastIndex = NSIndexPath(forRow: self.messages.count - 1, inSection: 0) self.messageTableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)
работа Идеально подходит для меня.
источник
Детали
Код
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 } }
источник
Я хотел, чтобы таблица загружалась концом таблицы, показанным в кадре. Я нашел использование
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.
источник
scrollToRowAtIndexPath
вообще нужно звонить ? Вы уже звонитеsetContentOffset
потом, что может сделать первый звонок бессмысленным.Для Swift:
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) }
источник
UITableViewScrollPositionBottom
Вместо этого вы должны использовать .источник
Для 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) }
источник
Это конечно жучок. Возможно, где-то в вашем коде вы используете
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) })
источник
После долгой возни вот что сработало для меня:
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() }
Ключ оказался не оборачивать
scrollToRowAtIndexPath
внутри ,dispatch_async
как предполагают некоторые, но просто после его вызоваlayoutIfNeeded
.Насколько я понимаю, вызов метода прокрутки в текущем потоке гарантирует, что смещение прокрутки устанавливается немедленно, до отображения представления. Когда я отправлял в основной поток, представление отображалось на мгновение, прежде чем прокрутка вступила в силу.
(Также NB, вам нужен
viewHasAppeared
флаг, потому что вы не хотите, чтобы он вызываетсяgoToBottom
каждый разviewDidLayoutSubviews
. Он вызывается, например, при изменении ориентации.)источник
Используя приведенные выше решения, это приведет к прокрутке до конца вашей таблицы (только если содержимое таблицы загружено первым):
//Scroll to bottom of table CGSize tableSize = myTableView.contentSize; [myTableView setContentOffset:CGPointMake(0, tableSize.height)];
источник
В Swift 3.0
self.tableViewFeeds.setContentOffset(CGPoint(x: 0, y: CGFLOAT_MAX), animated: true)
источник
Если вам нужно загружать данные асинхронно перед прокруткой вниз, вот возможное решение:
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 } } } }
источник
Функция на 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) } }
источник
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) }
или он не будет прокручиваться вниз.
источник
Используйте этот простой код для прокрутки tableView снизу
NSInteger rows = [tableName numberOfRowsInSection:0]; if(rows > 0) { [tableName scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:rows-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }
источник
Спасибо Джейкобу за ответ. действительно полезно, если кому-то интересно с монотачной версией С #
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 ); } }
источник
В 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
источник
[self.tableViewInfo scrollRectToVisible: CGRectMake (0, self.tableViewInfo.contentSize.height-self.tableViewInfo.height, self.tableViewInfo.width, self.tableViewInfo.height) анимировано: ДА];
источник
Принятый ответ не работал с моей таблицей (тысячи строк, динамическая загрузка), но приведенный ниже код работает:
- (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]; } }
источник
Нет необходимости в прокрутке, вы можете просто сделать это с помощью этого кода:
[YOURTABLEVIEWNAME setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
источник
Если вы программно настраиваете фрейм для tableview, убедитесь, что вы правильно устанавливаете фрейм.
источник
На iOS 12 принятый ответ кажется неверным. Я работал со следующим расширением
import UIKit extension UITableView { public func scrollToBottom(animated: Bool = true) { guard let dataSource = dataSource else { return } let sections = dataSource.numberOfSections?(in: self) ?? 1 let rows = dataSource.tableView(self, numberOfRowsInSection: sections-1) let bottomIndex = IndexPath(item: rows - 1, section: sections - 1) scrollToRow(at: bottomIndex, at: .bottom, animated: animated) } }
источник
В 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) } }
источник
Я считаю, что старые решения не работают с swift3.
Если вы знаете числовые строки в таблице, вы можете использовать:
tableView.scrollToRow( at: IndexPath(item: listCountInSection-1, section: sectionCount - 1 ), at: .top, animated: true)
источник