Ответ 1
Я верю, что вызов tableView.setContentOffset(CGPoint(x: 0, y: CGFloat.greatestFiniteMagnitude), animated: false)
сделает то, что вы хотите.
У меня есть UITableView
, который заполняется ячейками переменной высоты. Я бы хотел, чтобы таблица прокручивалась вниз, когда представление было введено в действие.
В настоящее время у меня есть следующая функция
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[log count]-1 inSection:0];
[self.table scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
log - это изменяемый массив, содержащий объекты, составляющие содержимое каждой ячейки.
Приведенный выше код отлично работает в viewDidAppear
, однако у этого есть неудачный побочный эффект отображения верхней части таблицы, когда сначала открывается представление, а затем прыгает вниз. Я бы предпочел, чтобы table view
можно было прокручивать снизу до появления.
Я пробовал прокрутку в viewWillAppear
и viewDidLoad
, но в обоих случаях данные еще не были загружены в таблицу, и оба генерируют исключение.
Любое руководство было бы высоко оценено, даже если это всего лишь случай, когда я рассказываю, что у меня есть все, что возможно.
Я верю, что вызов tableView.setContentOffset(CGPoint(x: 0, y: CGFloat.greatestFiniteMagnitude), animated: false)
сделает то, что вы хотите.
От ответ Джейкоба, это код:
- (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];
}
Я использую автозапуск, и ни один из ответов не работал у меня. Вот мое решение, которое наконец-то сработало:
@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)];
}
}
принятое решение от @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)
}
}
}
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
}
}
На самом деле "Swifter" способ сделать это в быстрой:
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.
Для Свифта:
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)
})
Используя приведенные выше решения, это будет прокручиваться до нижней части таблицы (только если сначала загружается содержимое таблицы):
//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
.
Мое понимание этого заключается в том, что вызов метода прокрутки в текущем потоке гарантирует, что смещение прокрутки будет установлено сразу, прежде чем будет отображаться представление. Когда я отправлялся в основной поток, представление отображалось на мгновение до того, как прокрутка вступила в силу.
(Также NB вам нужен флаг viewHasAppeared
, потому что вы не хотите goToBottom
каждый раз, когда вызывается viewDidLayoutSubviews
. Он вызывается, например, всякий раз, когда меняется ориентация.)
В Swift 3.0
self.tableViewFeeds.setContentOffset(CGPoint(x: 0, y: CGFLOAT_MAX), animated: true)
Спасибо Джейкобу за ответ. действительно полезно, если кому-то интересно с monotouch С# версии
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
}
}
}
}
Функция быстро <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)
}
или он не будет прокручиваться до нижней части.
В 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) анимированный: YES];
Принятый ответ не работал с моей таблицей (тысячи строк, динамическая загрузка), но приведенный ниже код работает:
- (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)];
Если вы программно настраиваете фрейм для табличного обзора, убедитесь, что вы правильно устанавливаете кадр.
В Swift вам просто нужно
self.tableView.scrollToNearestSelectedRowAtScrollPosition(UITableViewScrollPosition.Bottom, animated: true)
чтобы он автоматически прокручивался до buttom
В быстрой версии 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)