使用UITableView的scrollToRowAtIndexPath不起作用

时间:2014-10-07 20:03:21

标签: uitableview swift ios8 xcode6

我在iOS8中有一个像这样的表格视图:

tableView = UITableView(frame: view.bounds, style: .Plain)
view.addSubview(tableView)

当用户在键盘中键入并发送一些文本时,应用程序会调用以下方法来滚动tableView。目标是在屏幕上查看新文本(如聊天)

let numberOfRows = tableView.numberOfRowsInSection(0)
        if numberOfRows > 0 {
            let indexPath = NSIndexPath(forRow: numberOfRows-1, inSection: 0)
            tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)
        }

但表视图不会滚动到bootom。

有人有解决方案吗?

谢谢。

说明:

班级定义:

class ChatViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextViewDelegate 

然后我有了表视图的定义:

var tableView: UITableView! 

在viewDidLoad中:

tableView = UITableView(frame: view.bounds, style: .Plain) 
tableView.dataSource = self 
tableView.delegate = self 
view.addSubview(tableView) 

然后我调用了应该进行滚动的代码(我的答案中的第二个代码块)。 当我启动应用程序时,我希望tableview向下滚动,但它不起作用。

16 个答案:

答案 0 :(得分:75)

以下解决方案对我有用。它是StackOverflow上的解决方案组合。经过短暂的延迟,我打电话给“scrollToRowAtIndexPath”。

func tableViewScrollToBottom(animated: Bool) {

    let delay = 0.1 * Double(NSEC_PER_SEC)
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

    dispatch_after(time, dispatch_get_main_queue(), {

        let numberOfSections = self.tableView.numberOfSections()
        let numberOfRows = self.tableView.numberOfRowsInSection(numberOfSections-1)

        if numberOfRows > 0 {
            let indexPath = NSIndexPath(forRow: numberOfRows-1, inSection: (numberOfSections-1))
            self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)
        }

    })
}

呼叫:

tableViewScrollToBottom(true)

Swift 3

func tableViewScrollToBottom(animated: Bool) {
    DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {
        let numberOfSections = self.tableView.numberOfSections
        let numberOfRows = self.tableView.numberOfRows(inSection: numberOfSections-1)

        if numberOfRows > 0 {
            let indexPath = IndexPath(row: numberOfRows-1, section: (numberOfSections-1))
            self.tableView.scrollToRow(at: indexPath, at: .bottom, animated: animated)
        }
    }
}

答案 1 :(得分:9)

我的问题的解决方案是:

let numberOfSections = tableView.numberOfSections()
let numberOfRows = tableView.numberOfRowsInSection(numberOfSections-1)

if numberOfRows > 0 {
    println(numberOfSections)
    let indexPath = NSIndexPath(forRow: numberOfRows-1, inSection: (numberOfSections-1))
    tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)
}

答案 2 :(得分:7)

在调用scroll之前先尝试重新加载。很受欢迎,但适用于iOS8。

   tableView.reloadData()
   tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)

答案 3 :(得分:6)

@ Fox5150的SWIFT 3版本答案,附带扩展名:

extension UITableView {

    func tableViewScrollToBottom(animated: Bool) {

        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {

            let numberOfSections = self.numberOfSections
            let numberOfRows = self.numberOfRows(inSection: numberOfSections-1)
            if numberOfRows > 0 {
                let indexPath = IndexPath(row: numberOfRows-1, section: (numberOfSections-1))
                self.scrollToRow(at: indexPath, at: UITableViewScrollPosition.bottom, animated: animated)
            }
        }
    }
}

<强> USAGE:

self.tableView.tableViewScrollToBottom(animated: true)

答案 4 :(得分:2)

我有一个更大的索引的问题,甚至是15.只有5-6的索引才能使用。通过制作“animated:false”,scrollToRowAtIndexPath()完美地运作。

答案 5 :(得分:1)

更好的解决方案是颠倒tableView,以便您可以显示新消息  -insertRowsAtIndexPaths:withRowAnimation:

要做到这一点,你需要先通过以下方式翻转你的桌子:

_tableView.transform = CGAffineTransformMakeScale (1,-1);
然后不要忘记翻转你的细胞,通过子类化在-awakeFromNib中做到最好的地方:

- (void)awakeFromNib {
    [super awakeFromNib];
    self.contentView.transform = CGAffineTransformMakeScale (1,-1);

//if you have accessoryView
    self.accessoryView.transform = CGAffineTransformMakeScale (1,-1);
}

答案 6 :(得分:1)

尝试以下方法:

if tableView.numberOfRows(inSection: 0) > 0 {
    tableView.scrollToRow(at: IndexPath(row: ROW, section: SECTION), at: .top, animated: false)
}

答案 7 :(得分:0)

如果键盘仍然可见,则必须设置UITableView的{​​{1}}属性以补偿屏幕底部的键盘高度。否则您的单元格可能隐藏在键盘后面,因为contentInset并不知道其中一半内容被隐藏。

或使用自动处理的UITableView

答案 8 :(得分:0)

在加载tableview之后调用scrollToLastPosition()方法,如从viewWillAppear()调用或在表视图重新加载后将某些内容更改为tableview

func scrollToLastPosition() {
 if !message.isEmpty {
    let indexpath = NSIndexPath(forRow: message.count - 1 , inSection:     0)
    self.tableView.scrollToRowAtIndexPath(indexpath, atScrollPosition: .Bottom, animated: true)
}
}

答案 9 :(得分:0)

Heres Swift 3版

let numberOfSections = self.tableView.numberOfSections
let numberOfRows = self.tableView.numberOfRows(inSection: numberOfSections-1)

if numberOfRows > 0 {
    let indexPath = NSIndexPath.init(row: numberOfRows-1, section: numberOfSections-1)
    self.tableView.scrollToRow(at: indexPath as IndexPath, at: UITableViewScrollPosition.bottom, animated: animated)
}

答案 10 :(得分:0)

// First figure out how many sections there are
 let lastSectionIndex = self.tblTableView!.numberOfSections() - 1

// Then grab the number of rows in the last section

let lastRowIndex = 
self.tblTableView!.numberOfRowsInSection(lastSectionIndex) - 1

// Now just construct the index path

let pathToLastRow = NSIndexPath(forRow: lastRowIndex, inSection: lastSectionIndex)

// Make the last row visible
self.tblTableView?.scrollToRowAtIndexPath(pathToLastRow, atScrollPosition: UITableViewScrollPosition.None, animated: true)

答案 11 :(得分:0)

很简单。只需在 viewDidLayoutSubViews()

中进行滚动操作即可
override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.scrollToBottom(animated: false)
}

fileprivate func scrollToBottom(animated: Bool) {
    if self.items.count > 0 {
        let lastIndex = IndexPath(row: items.count - 1, section: 1)
        self.tableView.scrollToRow(at: lastIndex, at: .bottom, animated: animated)
    }
}

看似tableview可以在布局子视图后获得正确的位置。

答案 12 :(得分:0)

我知道这是一个较旧的线程,但是仍然有用。除了处理有时可能无法及时安排的超时外,还可以在主线程上使用同步块(通常不是我愿意做的事,但是我们讲的是毫秒):

def __str__(self):
    return '{}-{}'.format(self.industry, self.get_risk_display())

这总是对我有用。

答案 13 :(得分:0)

我通过在`viewWillLayoutSubviews()中调用scrollToRow()解决了该问题

答案 14 :(得分:0)

我在2020年末遇到同样的问题。

由于我真的不想要一些不可思议的调度超时,所以我玩了一些。帮助(并且在此之前未提及)的是UITableView的强制布局:

_viewTable.layoutIfNeeded()
_viewTable.scrollToRow(at:IndexPath(row:index, section:0), at:.middle, animated:false)

答案 15 :(得分:-1)

以上所有代码都可以,但在我的情况下,我想加载tableView以及当时立即滚动到tableView 的底部控制器加载,对于上述情况,上述方法需要一些时间才能滚动到tableView的底部。所以我遵循了这些代码。

覆盖tableView重新加载为

extension UITableView
{
    func reloadData(completion: @escaping ()->()) {
        UIView.animate(withDuration: 0, animations: { self.reloadData() })
        { _ in completion() }
    }
}

写入滚动到底部的方法如下:

func tableViewScrollToBottom
{
     if self.tblChat.contentSize.height > self.tblChat.frame.size.height
     {
         let offset:CGPoint = CGPoint(x: 0,y :self.tblChat.contentSize.height-self.tblChat.frame.size.height)
         self.tblChat.setContentOffset(offset, animated: false)
     }
 }

然后在从Web服务或任何核心数据实体加载数据时重新加载tableView

tblChat.reloadData()
{
     self.tableViewScrollToBottom
}

现在我的工作顺利进行。