View.traitCollection.horizontalSizeClass возвращает undefined (0) в viewDidLoad
Я использую UITextView внутри UIPageViewController, и я хочу определить размер шрифта на основе класса размера устройства.
Первый слайд просмотра страницы загружается в ViewDidLoad так (viewControllerAtIndex(0)
):
override func viewDidLoad() {
super.viewDidLoad()
//Some unrelated code here
// Page View Controller for Questions Slider
questionPageVC = storyboard?.instantiateViewControllerWithIdentifier("QuestionPageView") as? UIPageViewController
questionPageVC!.dataSource = self;
questionPageVC!.delegate = self;
let startingViewController : QuestionContentViewController = viewControllerAtIndex(0) as QuestionContentViewController
var viewControllers = [startingViewController]
questionPageVC!.setViewControllers(viewControllers, direction: .Forward, animated: true, completion: nil)
let sliderHeight = view.frame.size.height * 0.5
questionPageVC!.view.frame = CGRectMake(20, 70,
view.frame.size.width-40, sliderHeight)
addChildViewController(questionPageVC!)
view.addSubview(questionPageVC!.view!)
questionPageVC?.didMoveToParentViewController(self)
var pageControl : UIPageControl = UIPageControl.appearance()
pageControl.pageIndicatorTintColor = UIColor.lightGrayColor()
pageControl.currentPageIndicatorTintColor = UIColor.blackColor()
pageControl.backgroundColor = UIColor.whiteColor()
// Some more code here
}
И затем, в viewControllerAtIndex:
private func viewControllerAtIndex(index: Int) -> QuestionContentViewController {
var pcvc : QuestionContentViewController = storyboard?.instantiateViewControllerWithIdentifier("QuestionContentView") as! QuestionContentViewController
var fontSize = ""
if (view.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Compact) {
fontSize = "20"
} else {
fontSize = "28"
}
pcvc.questionString = TextFormatter(string: fontSize + questionsArray[index]).formattedString
pcvc.questionIndex = index
return pcvc
}
Проблема в том, что самый первый слайд, который был вызван в viewDidLoad, всегда использует размер шрифта в предложении else.
Если я печатаю view.traitCollection.horizontalSizeClass
, для этого первого слайда я получаю 0 (UIUserInterfaceSizeClassUnspecified
), для последующих слайдов я получаю правильный размер.
Я попробовал переместить все это в "viewWillAppear", а затем с UIPageViewController произойдут странные вещи (дополнительный слайд с неправильным размером текста за другими слайдами)
Ответы
Ответ 1
Проблема в том, что viewDidLoad
слишком рано спрашивать о коллекции представлений. Это связано с тем, что коллекция признаков представления представляет собой функцию, полученную из иерархии представлений, в среде, в которой она находится. Но в viewDidLoad
представление не имеет среды: оно еще не находится в иерархии представлений. Он загружен, что означает, что он существует: теперь у контроллера вида есть представление. Но он еще не был помещен в интерфейс, и он не будет помещен в интерфейс до тех пор, пока не будет viewWillAppear:
, который появится позже в последовательности событий.
Однако диспетчер представлений также имеет коллекцию признаков, и у него есть среда: к моменту вызова viewDidLoad
контроллер представления является частью иерархии контроллера представления. Поэтому самым простым (и правильным) решением является запрос traitCollection
self
, а не view
. Просто скажите self.traitCollection
, где у вас теперь есть view.traitCollection
, и все будет хорошо.
(Ваше решение, запрашивающее экран для его коллекции признаков, может работать, но оно не является надежным и не является правильным. Это связано с тем, что родительский контроллер просмотра может изменять коллекцию признаков своего child, и если вы обойдете правильный подход и спросите экран, прямо, вы не получите правильную коллекцию признаков.)
Ответ 2
Я обнаружил, что если я использую основной экран traitCollection, вместо текущего представления, я получаю правильный класс размера:
if (UIScreen.mainScreen().traitCollection.horizontalSizeClass == UIUserInterfaceSizeClass.Compact) {
fontSize = "20"
} else {
fontSize = "28"
}
Ответ 3
Вам будет лучше перемещать этот код в метод viewWillAppear, так как в viewDidLoad представление ViewController еще не добавлено в иерархию, и вы можете получить пустую коллекцию признаков.
Ответ 4
В моем случае мне нужно было, чтобы мой взгляд знал о horizontalSizeClass, поэтому доступ к traitCollection UIScreen был заманчивым, но не поощрялся, поэтому у меня было что-то вроде этого:
override func layoutSubviews() {
super.layoutSubviews()
print("\(self.traitCollection.horizontalSizeClass.rawValue)")
switch self.traitCollection.horizontalSizeClass {
case .regular, .unspecified:
fontSize = 28
case .compact:
fontSize = 20
}
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
print("\(self.traitCollection.horizontalSizeClass.rawValue)")
guard let previousTraitCollection = previousTraitCollection else { return }
if self.traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass {
layoutIfNeeded()
}
}