Как прокрутить до нижней части 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 но в обоих случаях данные не были загружены в таблицу еще и как исключение.
любое руководство было бы очень ценно, даже если это просто случай сказать мне, что у меня есть все, что возможно.
30 ответов:
Я считаю, что вызов
[table setContentOffset:CGPointMake(0, CGFLOAT_MAX)]будет делать то, что вы хотите.
С ответ Якоба этот код:
- (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]; } }
Я думаю, самый простой способ это:
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) }
Если вам нужно прокрутить до точного конца содержимого, вы можете сделать это следующим образом:
- (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]; }
Я использую 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)]; } }
The принятое решение @JacobRelkin не работает для меня в iOS 7.0 с помощью автоматической компоновки.
у меня есть пользовательский подкласс
UIViewControllerи добавил переменную экземпляра_tableViewкак подвида егоview. Я позиционировал_tableViewиспользование автоматической компоновки. Я попытался вызвать этот метод в конце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) } } }
подробности
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)
на самом деле" более быстрый " способ сделать это в swift :
var lastIndex = NSIndexPath(forRow: self.messages.count - 1, inSection: 0) self.messageTableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)работа идеально подходит для меня.
Я хотел, чтобы таблица загружалась с конца таблицы, показанной в кадре. Я нашел с помощью
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.
Для 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) }
Для 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) })
используя вышеуказанные решения, это будет в нижней части таблицы (только если содержимое таблицы загружается первой):
//Scroll to bottom of table CGSize tableSize = myTableView.contentSize; [myTableView setContentOffset:CGPointMake(0, tableSize.height)];
после долгой возни это то, что сработало для меня:
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.мое понимание этого заключается в вызове метода прокрутки в настоящее поток гарантирует, что смещение прокрутки устанавливается немедленно,до вид. Когда я отправлялся на главную thread, представление было отображено за мгновение до того, как свиток вступил в силу.
(также NB вам нужно
viewHasAppearedфлаг, потому что вы не хотитеgoToBottomкаждый разviewDidLayoutSubviewsназывается. Он вызывается, например, всякий раз, когда меняется ориентация.)
спасибо Джейкобу за ответ. действительно полезно, если кто-нибудь интересен с monotouch c# version
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 ); } }
используйте этот простой код для прокрутки tableView снизу
NSInteger rows = [tableName numberOfRowsInSection:0]; if(rows > 0) { [tableName scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:rows-1 inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES]; }
Если вам нужно загрузить данные асинхронно перед прокруткой вниз, вот возможное решение:
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 } } } }
функция on 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) } }
в 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.высота-самость.tableViewInfo.рост, самость.tableViewInfo.ширина, собственная личность.tableViewInfo.высота) анимированные: да];
принятый ответ не работал с моей таблицей (тысячи строк, динамическая загрузка), но код ниже работает:
- (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 программно, убедитесь, что вы устанавливаете фрейм правильно.
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) }или он не будет прокручивать вниз.
в Swift, вам просто необходимо
self.tableView.scrollToNearestSelectedRowAtScrollPosition(UITableViewScrollPosition.Bottom, animated: true)чтобы он автоматически прокручивался до кнопки
в swift 3.0 Если вы хотите перейти к какой-либо конкретной ячейке tableview, измените значение индекса ячейки, например, измените "self.твой Арр.графа" значение .
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)
Comments