0
votes

I have a trouble with loading view controller from xib

I have a xib file which contains a view controller and a subview inside it as the image below. Notice that I'm using iPhone 11 Pro Max in xib (which have screen width = 414)

The subview has 8 leading and trailing to its parent.

enter image description here

The problem is when i run the app on iPhone 12 Pro Max (which have screen width = 428), I check values of screen size and the subview size and it returns strange values. Here is my code:


public override func viewDidLoad() {
        super.viewDidLoad()
        
        print(view.frame) // (0.0, 0.0, 414.0, 896.0)
        print(collageView.frame) // (8.0, 210.0, 398.0, 398.0)

    }
    
    public override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        
        print(view.frame) // (0.0, 0.0, 428.0, 926.0) updated
        print(collageView.frame) // (8.0, 210.0, 398.0, 398.0) ??
        
        let width = collageView.frame.width
        let height = collageView.frame.height
        
        let frames = self.frames?(CGSize(width: width, height: height)) ?? []
        
        for i in 0..<frames.count {
            let componentView = CropComponentView(frame: frames[i])
            componentView.image = images[i]
            collageView.addSubview(componentView)
        }
    }
  

My questions are:

How can we get the properly screen size inside viewDidLoad ? why the subview's frame doesn't update like screen size does ?

1
You cannot get any size information in viewDidLoad. It's too early. programmingios.net/premature-layoutmatt
@matt I accept that but how the question about the subview's frame. And how can the subview have the correct frame ?Tung Vu Duc
@TungVuDuc Try layoutIfNeeded() and then check frame in viewdidload. Let me know either it works or notdahiya_boy
@dahiya_boy call layoutIfNeeded() inside viewDidLayoutSubviews bellow super.viewDidLayoutSubviews() then the collageView's frame is updatedTung Vu Duc
Also, this is not crucial, but you should delete the Center X constraint, as it is not needed. If the view has leading and trailing constraints equal to each other, it is horizontally centered by definition.matt

1 Answers

1
votes

How can we get the properly screen size inside viewDidLoad ?

The sort answer is you can not get the final view(of the viewController) size in the viewDidLoad() because the view is just loaded from the xib and has the placeholder frames that was set in the xib. It needs to be added to the view hierarchy(e.g. to a parent view / window) in order for then the layout rules to be applied. The view will be added right after the view has been loaded.

The width/height that will be available for your controller is decided by the container controller(if any) and the device orientation and status bar state. For example if your controller is added in a tabbarcontroller it will have less vertical space if the tabbar is showing. If the statusbar is displayed and you have an incoming phone call the size of the status bar will change leaving less vertical space. If you display you controller in a SplitViewController container then it will have less width etc.

If you make the assumption that it will take the whole screen size you can calculate the frame in the viewDidLoad():

    override func viewDidLoad()  {
       //...
       var screenSize = UIScreen.main.bounds
       var collageViewFrame: CGSize = self.collageView.frame.sizeThatFits(screenSize)
    } 

why the subview's frame doesn't update like screen size does ?

From the documentation for -viewDidLayoutSubviews :

However, this method being called does not indicate that the individual layouts of the view's subviews have been adjusted.

If you need the correct frame you need to call layoutIfNeeded method in that subview. Se also this answer.