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)
}
しかし、テーブルビューは、ブースにスクロールしません。
誰かが解決策を持っていますか?
ありがとうございました。
説明:
クラスの定義:
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)
次に、スクロールを行う必要のあるコードを呼び出します(回答の2番目のコードブロック)。アプリケーションを起動すると、tableviewが下にスクロールするはずですが、機能しません。
以下の解決策は私のために働いた。 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
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)
}
}
}
私の問題の解決策は次のとおりです。
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)
}
スクロールを呼び出す前に、最初にリロードしてみてください。非常に奇妙ですが、iOS8で動作します。
tableView.reloadData()
tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: UITableViewScrollPosition.Bottom, animated: animated)
@ 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)
}
}
}
}
使用法:
self.tableView.tableViewScrollToBottom(animated: true)
簡単だ。 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が正しい位置を取得できるようです。
インデックスが15を超えると、大きな問題が発生します。5〜6までのインデックスしか使用できません。 「アニメーション:false」を作成することにより、scrollToRowAtIndexPath()は完全に機能しました。
より良い解決策は、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);
}
`viewWillLayoutSubviews()でscrollToRow()
を呼び出すことで問題を解決しました
キーボードがまだ表示されている場合は、UITableView
のcontentInset
プロパティを設定して、画面下部のキーボードの高さを補正する必要があります。そうしないと、UITableView
はコンテンツの半分がセルによって隠されていることを知らないため、セルがキーボードの後ろに隠れている可能性があります。
または、それを自動的に処理するUITableViewController
を使用します。
私はこれが古いスレッドであることを知っていますが、それでも関連があります。タイミングがうまく取れない場合があるタイムアウトを処理する代わりに、メインスレッドで同期ブロックを使用します(通常、私は何もしませんが、ミリ秒を話しています)。
DispatchQueue.main.sync {
// Reload code goes here...
tableView.reloadData()
}
DispatchQueue.main.sync {
// Row, section and other checks / initialization go here...
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
}
これは私にとって常に有効です。
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)
}
ViewWillAppear()からの呼び出しのようにtableviewを読み込んだ後、または何かがtableviewに変更されたときにtable viewを再読み込みした後にscrollToLastPosition()メソッドを呼び出します
func scrollToLastPosition() {
if !message.isEmpty {
let indexpath = NSIndexPath(forRow: message.count - 1 , inSection: 0)
self.tableView.scrollToRowAtIndexPath(indexpath, atScrollPosition: .Bottom, animated: true)
}
}
// 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)