簡體   English   中英

為什么呈現模式UIViewController會在呈現控制器上導致setNeedsLayout?

[英]Why does presenting a modal UIViewController cause setNeedsLayout on the presenting controller?

似乎呈現和關閉視圖控制器都提示呈現視圖布局其子視圖和/或更新其約束。 在繁重的視圖層次結構中,這會引入性能問題。 再次-這是現有的,當前顯示的視圖。 創建和顯示的模態非常輕。

無論我是否使用自動布局(在示例項目中),都會發生這種情況。

我已經建立了一個演示項目 ,該項目近似於我正在開發的應用程序。 有一個主父控制器,帶有一個水平滾動的UIScrollView 將多個子控制器添加到父控制器,並將其視圖添加到滾動視圖並使用NSLayoutConstraint排列。 每個子視圖本身都有一個子視圖,一個簡單的UIView ,它也帶有約束。

在導航欄中,有一個用於啟動模態的按鈕。 呈現時,父控制器會在每個子視圖上多次調用setNeedsLayout 在我的演示項目中,我將覆蓋setNeedsLayout以便在訪問它時進行記錄。 關閉模態時也會發生同樣的情況。 打開和關閉模態幾次,然后觀察控制台。

我看不出有什么理由需要新的布局,而在更復雜的視圖中,我發現正在觸發數百個此類調用,從而對性能產生了明顯影響。

請注意,當省略ChildView的布局代碼時,不會調用setNeedsLayout 我鼓勵您注釋掉約束,並查看日志記錄的區別。

為什么會這樣呢? 在呈現和消除模態時,如何防止不必要的布局通過?

首先,您正在記錄setNeedsLayout ,它只是一個標記機制,實際上還沒有任何工作。 多次調用setNeedsLayout可能僅觸發一個布局。 您應該改用-[UIView layoutSubviews]-[UIViewController viewDidLayoutSubviews]記錄日志,因為這些是實際的繁重工作。

其次,與布局相關的方法應在演示過程中快速重復地調用,因為:

  1. 窗口需要旋轉其所有子視圖,以遵守呈現的視圖控制器的首選界面方向。
  2. 動畫將需要知道視圖的初始狀態和最終狀態。
  3. 當出於某種原因在父視圖上發生布局時,它們的所有子視圖(可能包括視圖控制器的視圖)當然也需要更新其布局。

如果要最大程度地減少布局傳遞的次數,可以嘗試使用presentViewController:animated:放棄,而是使用addChildViewController:並手動為必要的視圖設置動畫。 但是即使那樣,您仍然可能仍然觸發父控制器的布局。

您正在做一件非常非常非常奇怪的事情:您正在維護一個具有10個子視圖控制器的自定義父視圖控制器,所有這些子視圖控制器同時在界面中 視圖控制器不是為這種事情而設計的。 這是觸發您看到的多個layoutSubviews調用的原因。 可以有多個子視圖控制器,但是它們的視圖不應該全部在層次結構中-特別是在您的情況下,實際上只有一個這樣的子視圖可見。

事實上,你已經構建的界面-尋呼滾動視圖,其每個“頁”是一個視圖控制器管理的視圖-為您UIPageViewController,這是更為有效,因為它實際上只維持已實施一次最多三個視圖控制器:視圖控制器管理滾動視圖內的可見視圖,視圖控制器管理左右視圖。 它也非常方便和易於使用。

所以:

  • 您應該使用 UIPageViewController,或者

  • 您應該模仿 UIPageViewController的功能,在視圖控制器滾動到視線之外時刪除視圖控制器的視圖(甚至釋放視圖控制器),就像我們在UIPageViewController出現之前所做的那樣-觀看WWDC的“高級滾動視圖技術”視頻2011年。在UIPageViewController出現之前,我的拉丁“抽認卡”應用以這種方式工作; 它有成千上萬個詞匯卡,每個詞匯卡都由一個視圖控制器管理,但是在任何時刻最多只能存在三個卡視圖控制器。

(順便說一句,您也不應該使用自己的self.childControllers可變數組,因為此列表已經為self.childViewControllers維護了。)

我認為layoutSubviews之所以會被調用是因為呈現控制器的view更改了超級視圖,同時一旦被呈現的視圖隱藏,就會動畫出屏幕。

如果您想在幀未更改時直接跳過layoutSubviews ,則只需保存對最后一幀的引用,如果返回相等,則不做任何事情。 另外,無需在子視圖上調用setNeedslayout ,因為如果您調整子視圖的大小,系統將自動觸發它。

無論如何,您的主要問題是您的方法:

  1. rootController 使用它們時才使用視圖控制器 (在選項卡欄控制器內部,推到導航控制器中,作為窗口的rootController ,以模態顯示等)。 如果要手動添加視圖,請不要使用視圖控制器,而要使用自定義視圖! 這是一個非常常見的錯誤,您可以在此處查看更多詳細信息。

  2. 延遲加載視圖和對象並重用它們 例如,您僅應加載1〜3頁內容,並且僅在用戶滾動到新頁面時才加載新內容。 加載新視圖時,請刪除其中一個舊視圖,或者最好重新使用它。


您不僅可以使用控制器來分離邏輯,還可以使用自定義視圖來分離邏輯。 在特定情況下不應該使用控制器的一些原因:

  • 手動添加控制器的視圖時,控制器不會被容器控制器或窗口保留。
  • 控制器將不會獲得方向,內存, viewDidAppear等事件。 同樣,因為您沒有將它們用作適當的視圖控制器。

如果您正確實現了自定義容器控制器 (需要做很多工作),則可以使用控制器。 否則,請堅持使用自定義視圖。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM