可変高のセルが配置された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 setContentOffset:CGPointMake(0, CGFLOAT_MAX)]
を呼び出すことはあなたが望むことをすると信じています。
Jacob's answer から、これはコードです:
- (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が受け入れた解決策 は、Auto Layoutを使用したiOS 7.0では機能しませんでした。
UIViewController
のカスタムサブクラスがあり、view
のサブビューとしてインスタンス変数_tableView
を追加しました。自動レイアウトを使用して_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];
}
}
viewDidLoad
の最後で[self tableViewScrollToBottomAnimated:NO]
を呼び出すと機能します。残念ながら、それはまた、tableView:heightForRowAtIndexPath:
がすべてのセルに対して3回呼び出される原因にもなります。
以下は、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
}
}
実際、Swiftでそれを行う「Swifter」の方法は次のとおりです。
var lastIndex = NSIndexPath(forRow: self.messages.count - 1, inSection: 0)
self.messageTableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Bottom, animated: true)
私にぴったり。
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)
}
フレームに表示されているテーブルの最後にテーブルをロードしたかったのです。を使用して見つけた
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:([self.tableView numberOfRowsInSection:0] - 1) inSection:0];
[[self tableView] scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
テーブルの高さがフレームの高さより低い場合にエラーが発生したため、機能しませんでした。テーブルにはセクションが1つしかありません。
私のために働いたソリューションは、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は、viewDidLoadでTRUEに設定されます。
代わりに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()
}
キーはnotであることが判明しました。一部の人が示唆しているようにdispatch_async
の内側にscrollToRowAtIndexPath
をラップしていますが、それに続いてlayoutIfNeeded
への呼び出しが続きます。
これについての私の理解は、currentスレッドでscrollメソッドを呼び出すと、スクロールオフセットがすぐに設定されることを保証し、beforeビューが表示されます。メインスレッドにディスパッチしているとき、スクロールが有効になる前にビューが一瞬表示されていました。
(また、NB viewHasAppeared
が必要なのは、goToBottom
が呼び出されるたびにviewDidLayoutSubviews
が必要ないためです。たとえば、向きが変わるたびに呼び出されます。 )
Swift 3.0で
self.tableViewFeeds.setContentOffset(CGPoint(x: 0, y: CGFLOAT_MAX), animated: true)
上記のソリューションを使用すると、テーブルの一番下までスクロールします(テーブルのコンテンツが最初にロードされた場合のみ):
//Scroll to bottom of table
CGSize tableSize = myTableView.contentSize;
[myTableView setContentOffset:CGPointMake(0, tableSize.height)];
答えてくれたジェイコブに感謝します。モノタッチC#バージョンに興味のある方なら本当に助かります
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.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一番下までスクロール
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];
}
テーブルビューのフレームをプログラムで設定している場合は、フレームを正しく設定していることを確認してください。
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
から呼び出す必要があります
次のコードを使用すると、スクロールする必要はありません。
[YOURTABLEVIEWNAME setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
[self.tableViewInfo scrollRectToVisible:CGRectMake(0、self.tableViewInfo.contentSize.height-self.tableViewInfo.height、self.tableViewInfo.width、self.tableViewInfo.height)animated: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];
}
}
Swiftでは、必要なのは
self.tableView.scrollToNearestSelectedRowAtScrollPosition(UITableViewScrollPosition.Bottom, animated: true)
自動的に底までスクロールする
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)
}
}
次のような別の良い方法を見つけました。
func yourFunc() {
//tableView.reloadData()
self.perform(#selector(scrollToBottom), with: nil, afterDelay: 0.1)
}
@objc func scrollToBottom() {
self.tableView.scrollToRow(at: IndexPath(row: 0, section: self.mesArr.count - 1), at: .bottom, animated: false)
}
TableViewの下部をスクロールする最も安全な方法は、「tableView.scrollRectToVisible」を使用することです。 tableView.reloadData()を呼び出した後に使用します。 In Swift 5
private func scrollAtTheBottom() {
let lastIndexPath = IndexPath(row: state.myItemsArray.count - 1, section: 0)
let lastCellPosition = tableView.rectForRow(at: lastIndexPath)
tableView.scrollRectToVisible(lastCellPosition, animated: true)
}
古いソリューションはSwift3では機能しないと思います。
テーブルの行数がわかっている場合は、次を使用できます。
tableView.scrollToRow(
at: IndexPath(item: listCountInSection-1, section: sectionCount - 1 ),
at: .top,
animated: true)
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)
}
}