預測iOS 13中的大小類

若是您依賴於大小更改來構建自適應佈局,則應該檢查iOS 13的代碼.UIKit如今能夠預測視圖的初始特徵,所以您不能假設traitCollectionDidChange在視圖首次添加到視圖層次結構時將調用它。bash

特徵集合和大小類

Apple在iOS 8中首次引入了特徵集合來描述用戶界面的環境屬性(特徵)。水平和垂直尺寸類特徵粗略地指示寬度或高度是否受約束(緊湊)或不受約束(常規)。ide

咱們的想法是構建佈局變體以適應緊湊和常規尺寸類。您能夠直接在Interface Builder中添加特徵變體,或者若是您願意,可使用如下方法:佈局

  • traitCollectionDidChange (查看控制器或視圖)
  • willTransition(to:with:) (查看控制器)

其中我對緊湊和常規尺寸寬度有不一樣的約束集。我根據水平尺寸類在約束之間切換:ui

private func enableConstraintsForWidth(_ horizontalSizeClass: UIUserInterfaceSizeClass) {
  if horizontalSizeClass == .regular {
    NSLayoutConstraint.deactivate(compactConstraints)
    NSLayoutConstraint.activate(regularConstraints)
  } else {
    NSLayoutConstraint.deactivate(regularConstraints)
    NSLayoutConstraint.activate(compactConstraints)
  }
}

複製代碼

切換髮生在traitCollectionDidChangespa

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
  super.traitCollectionDidChange(previousTraitCollection)
  if traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass {
    enableConstraintsForWidth(traitCollection.horizontalSizeClass)
  }
}

複製代碼

在iOS 12及更早版本中,UIKit traitCollectionDidChange在將視圖添加到視圖層次結構時調用該方法。這previousTraitCollectionnil第一次。當前值traitCollection在視圖控制器的屬性中可用。我依賴於在首次添加視圖時調用此方法以啓用正確的初始約束集。調試

iOS 13中的變化

在iOS 13中,在您將視圖添加到視圖層次結構以前,UIKit會在建立視圖時設置視圖的特徵。UIKit根據上下文猜想視圖的可能特徵。而後,當您將視圖添加到視圖層次結構時,實際特徵將從父級繼承。code

若是UIKit正確猜想,則在將視圖添加到視圖層次結構時,視圖的特徵集合不會更改。traitCollectionDidChange若是您依賴它來設置佈局的初始狀態,則再也不接收調用問題。blog

一種可能的解決方法是從viewDidLoad繼承

override func viewDidLoad() {
    super.viewDidLoad()
    ...
    enableConstraintsForWidth(traitCollection.horizontalSizeClass)
}

複製代碼

在iOS 12及更早版本中,Apple沒有承諾UIKit此時正確設置了視圖的特徵。可是,咱們應該調用traitCollectionDidChange什麼時候將視圖添加到層​​次結構中,以便咱們能夠更正。生命週期

在iOS 13中,這基於預測的特徵設置佈局的初始狀態。若是UIKit猜錯了,咱們會調用traitCollectionDidChange最終的size類。不管哪一種方式,咱們最終都獲得了正確配置的佈局。

佈局子視圖

Apple建議的另外一種方法是在其中一種佈局方法中執行涉及特徵的任何工做:

  • UIViewController.viewWillLayoutSubviews()
  • UIView.layoutSubviews()
  • UIViewController.viewDidLayoutSubviews()

特徵集合在佈局發生以前更新,所以在上述任何方法中都是最新的。這種方法惟一須要注意的是,在視圖控制器或視圖的生命週期中能夠屢次調用佈局方法,所以您應該採起措施避免重複工做:

private var firstTime = true
override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    if firstTime {
        firstTime = false
        enableConstraintsForWidth(traitCollection.horizontalSizeClass)
    }
}

複製代碼

咱們在第一次執行佈局時設置佈局狀態,而後依賴於traitCollectionDidChange任何將來的大小類更改。

我該怎麼辦?

檢查您的代碼是否有任何用途traitCollectionDidChange。若是您依賴於調用它來設置視圖的初始佈局,請從佈局子視圖方法之一或相似的地方調用您的設置代碼viewDidLoad

若是您只在Interface Builder中使用特徵變體,則無需執行任何操做。

調試特徵集合更改

最後一個提示。經過向方案添加啓動參數,您能夠在每次更改時記錄先前和當前特徵集合:

-UITraitCollectionChangeLoggingEnabled YES

複製代碼

不要忘記領先的「 - 」:

啓動參數-UITraitCollectionChangeLoggingEnabled YES

每次traitCollectionDidChange調用它都會記錄更改,前一個和當前的特徵集合:

[TraitCollectionChange] Sending -traitCollectionDidChange: to ...
  ► trait changes: { HorizontalSizeClass: Unspecified → Regular;
  VerticalSizeClass: Unspecified → Regular }
  ► previous: <UITraitCollection: 0x600003f2c6c0; DisplayScale = 1, ...
  ► current: <UITraitCollection: 0x600003f14540; DisplayScale = 1, ...

複製代碼

閱讀更多

相關文章
相關標籤/搜索