UITableView reloadData 滑不到底部

簡(jiǎn)介

最近有個(gè)需求,在 tableView reloadData結(jié)束后,需要滑動(dòng)到底部,可是總是不能準(zhǔn)確的滾動(dòng)到底部。自然而言的就想到了三個(gè)方法,查看了一下有關(guān)的文檔

  1. layoutSubviews
  2. setNeedsLayout
  3. layoutIfNeeded

layoutSubviews

Lays out subviews.

Discussion

Subclasses can override this method as needed to perform more precise layout of their subviews. You should override this method only if the autoresizing and constraint-based behaviors of the subviews do not offer the behavior you want. You can use your implementation to set the frame rectangles of your subviews directly.

You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.

在子類(lèi)中,如果你需要更加準(zhǔn)確的定位,你可以重寫(xiě)這個(gè)方法。如果 autoresizing 和 constraint不能為你提供你想要做的。你可以自己設(shè)置subviews的 frame。
你不應(yīng)該直接調(diào)用這個(gè)方法,如果你想要強(qiáng)制更新布局,應(yīng)該調(diào)用setNeedsLayout,在下一次繪圖更新之前,如果你想要立刻的更新布局,需要調(diào)用 layoutIfNeeded

setNeedsLayout

Invalidates the current layout of the receiver and triggers a layout update during the next update cycle.

Discussion

Call this method on your application’s main thread when you want to adjust the layout of a view’s subviews. This method makes a note of the request and returns immediately. Because this method does not force an immediate update, but instead waits for the next update cycle, you can use it to invalidate the layout of multiple views before any of those views are updated. This behavior allows you to consolidate all of your layout updates to one update cycle, which is usually better for performance.
你在想要更新 view 的 subviews 的布局的時(shí)候,可以在主線(xiàn)程調(diào)用此方法。此方法記錄請(qǐng)求并且立即返回。因?yàn)檫@個(gè)方法不強(qiáng)制立即更新,而是等待下一個(gè)周期更新,你可以使用此方法來(lái)讓很多 views 的布局失效,并且這樣做可以把所有布局更新合并到一個(gè)更新周期,這通常會(huì)提高性能。

layoutIfNeeded

Lays out the subviews immediately, if layout updates are pending.

Discussion

Use this method to force the view to update its layout immediately. When using Auto Layout, the layout engine updates the position of views as needed to satisfy changes in constraints. Using the view that receives the message as the root view, this method lays out the view subtree starting at the root. If no layout updates are pending, this method exits without modifying the layout or calling any layout-related callbacks.
使用此方法強(qiáng)制視圖立即更新其布局。使用“自動(dòng)布局”時(shí),布局引擎會(huì)根據(jù)需要更新視圖的位置,以滿(mǎn)足約束的更改,使用一個(gè) view 作為 rootView ,此方法從根開(kāi)始布局視圖子樹(shù)。如果沒(méi)有約束需要更新,此方法會(huì)退出,不會(huì)修改 layout 或者調(diào)用和此 layout 有關(guān)的回調(diào)。

stackoverflow上的提問(wèn)

在 stackoverflow上有查到一個(gè)問(wèn)題, How to tell when UITableView has completed ReloadData?,提問(wèn)的人想要滾動(dòng) tableView 到底部,發(fā)現(xiàn)調(diào)用直接 reloadData,然后滾動(dòng)沒(méi)有滾動(dòng)到最底部,提出了這個(gè)問(wèn)題。 這個(gè)下面有很多很多的答案,具體的如下:
1.調(diào)用layoutIfNeeded強(qiáng)制的刷新布局,接著執(zhí)行scrollToRowAtIndexPath,滾動(dòng)到底部,確實(shí)是幫助我們解決了這個(gè)問(wèn)題。

[self.tableView reloadData];
[self.tableView layoutIfNeeded];
 NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView     numberOfSections]-1)]-1) inSection: ([self.tableView numberOfSections]-1)];
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

原因:

The reload happens during the next layout pass, which normally happens when you return control to the run loop (after, say, your button action or whatever returns).
So one way to run something after the table view reloads is simply to force the table view to perform layout immediately
重新加載發(fā)生在下一個(gè)布局過(guò)程中,這通常發(fā)生在將控制返回到運(yùn)行循環(huán)時(shí)(例如,您的按鈕操作或任何返回之后)。
所以,在tableView reloads 后可以立刻強(qiáng)制更新布局。

2.調(diào)用dispatch_async(dispatch_get_main_queue(), ^{})

   [self.tableView reloadData];
    dispatch_async(dispatch_get_main_queue(), ^{
    NSIndexPath* indexPath = [NSIndexPath indexPathForRow: ([self.tableView numberOfRowsInSection:([self.tableView numberOfSections]-1)]-1) inSection:([self.tableView numberOfSections]-1)];

    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
    });

原因

depending on how big your table data source is, you can animate going to the bottom of the tableview in the same run loop. If you try your test code with a huge table, your trick of using GCD to delay scrolling until the next run loop will work, whereas immediately scrolling will fail. But anyways, thanks for this trick!
但是這種方式并不總是能解決問(wèn)題,使用GCD來(lái)延遲滑動(dòng)到下一個(gè) runloop,但是立即滑動(dòng)的話(huà),就會(huì)出錯(cuò)。

總結(jié)

如果你的 tableView 在 reloadData后,無(wú)法滑動(dòng)到底部,那么就可以這樣做,在reloadData后,調(diào)用 layoutIfNeeded,來(lái)強(qiáng)制進(jìn)行布局,然后在進(jìn)行 tableView的滑動(dòng)就可以了。

[self.tableView reloadData];
[self.tableView layoutIfNeeded];
//do somthing you want
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容