Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

view.traitCollection.horizontalSizeClass returning undefined (0) in viewDidLoad

Tags:

ios

swift

I'm using a UITextView inside a UIPageViewController, and I want to determine the font size based on the size class of the device.

The first slide of the page view is loaded in ViewDidLoad like so (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
}

And then, in 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

}

The problem is that the very first slide, which was called in viewDidLoad, always uses the font size in the "else" clause.

If I print view.traitCollection.horizontalSizeClass, for that first slide, I get 0 (UIUserInterfaceSizeClassUnspecified), for subsequent slides, I get the correct size.

I tried moving the whole thing to "viewWillAppear", and then weird things happen to the UIPageViewController (an extra slide with the wrong size text behind the other slides)

like image 800
coopersita Avatar asked May 02 '15 21:05

coopersita


2 Answers

The problem is that viewDidLoad is too soon to be asking about a view's trait collection. This is because the trait collection of a view is a feature acquired from the view hierarchy, the environment in which it finds itself. But in viewDidLoad, the view has no environment: it is not in in the view hierarchy yet. It has loaded, meaning that it exists: the view controller now has a view. But it has not been put into the interface yet, and it will not be put into the interface until viewDidAppear:, which comes later in the sequence of events.

However, the view controller also has a trait collection, and it does have an environment: by the time viewDidLoad is called, the view controller is part of the view controller hierarchy. Therefore the simplest (and correct) solution is to ask for the traitCollection of self, not of view. Just say self.traitCollection where you now have view.traitCollection, and all will be well.

(Your solution, asking the screen for its trait collection, may happen to work, but it is not reliable and is not the correct approach. This is because it is possible for the parent view controller to alter the trait collection of its child, and if you bypass the correct approach and ask the screen, directly, you will fail to get the correct trait collection.)

like image 77
matt Avatar answered Nov 02 '22 10:11

matt


I found that if I use the main screen's traitCollection, instead of the current view, I get the correct size class:

if (UIScreen.main.traitCollection.horizontalSizeClass == .compact) {
    fontSize = "20"
} else {
    fontSize = "28"
}
like image 21
coopersita Avatar answered Nov 02 '22 12:11

coopersita