8

For several years in Swift and ObjC I've used this technique to make a circular view:

view.layer.cornerRadius = view.frame.size.width / 2
view.clipsToBounds = true

When UILayoutConstraints in the Storyboard are fixed width / height there has been no problem putting this code in viewDidLoad, or in viewWillAppear. Built in iOS9.3SDK it runs fine in iOS10 etc.

iOS10SDK shows framesize completely different to the fixed size in the Storyboard, even up to viewWillAppear, and in viewDidLayoutSubviews etc. My options are:

1) do this in viewDidAppear (awful solution) 2) hardcode the cornerRadius (works fine, but awful)

This looks like a bug (as a fixed width/height set in Storyboard should never be changed without at least a warning in the console). Is it, or is there a different place for this code now? (screenshot of test code attached)

enter image description here

Peter
  • 1,022
  • 9
  • 12
  • 1
    All my IB generated views have new uninitialized frame size of {1000,1000} in viewDidLoad and many other parts of the code. including cellForRowAtIndexPath – Miro Sep 13 '16 at 16:58
  • I've found that using the constraint width/height directly instead of frame width height has been a reasonable solution. http://stackoverflow.com/questions/39475456/ios10-viewdidload-frame-width-height-not-initialized-correctly-anymore-1000-10 – Miro Sep 13 '16 at 17:32
  • Hi @Miro - exactly what I saw (1000 default). I also set the height directly. I've also had related problems with NSLayoutConstraints which implies Apple changed a bunch of stuff in the view layout code :-) – Peter Sep 13 '16 at 17:34

3 Answers3

7

In iOS 10, I met this issue right after I started to use Xcode 8 in june, when it was beta. This solution is needed:

Put layoutIfNeeded() right before your layer modifications:

self.view.layoutIfNeeded()

view.layer.cornerRadius = view.frame.size.width / 2
view.clipsToBounds = true

OR

place the code for corner radius to viewDidLayoutSubviews() method:

override func viewDidLayoutSubviews() {

    view.layer.cornerRadius = view.frame.size.width / 2
    view.clipsToBounds = true

}
pedrouan
  • 12,762
  • 3
  • 58
  • 74
4

This was bugging me all day today. I had the same issue in a few points I needed the correct frame size to draw custom UI elements, or apply style to views, particularly changing the corner radius. The solution I found was creating a subclass of UIViewController with the following implementation:

class BaseViewController: UIViewController {

    /** 
        This is a helper property and a helper method that will be called
        when the frame is calculated, but will prevent the formatting code
        being called more than once
    */
    private var didCalculateInitialFrame = false
    private func checkIfFrameWasCalculated() {
        if self.didCalculateInitialFrame == false {
            self.viewDidCalculateInitialFrame()
            self.didCalculateInitialFrame = true
        }
    }

    //-- This is where you will tie your helper method with the view lifecycle
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        self.checkIfFrameWasCalculated()
    }

    /** 
        This is an overridable function that you will implement 
        in your subclasses, in case you need to use this approach
        in multiple places of your app. 
    */
    func viewDidCalculateInitialFrame() {

    }
}

This fixed all my issues with the storyboard. I hope this is helpful.

Alex L
  • 111
  • 2
  • Hi Alex - that is very helpful (upvoted). I've only held off on accepting as the answer as I feel there has to be a 'proper' way to do this and this feels like a temporary workaround. Thanks v much for the answer. – Peter Sep 17 '16 at 05:52
  • Peter, thanks - totally with you! If the proper way gets documented, I'm definitely updating this answer. In any case, I shared the project I used to play with the new view controller lifecycle, and how and when view frames are calculated in iOS 10 / Xcode 8.0 GM. You can find it here: [link](https://github.com/al7/TestViewDidLoad). – Alex L Sep 17 '16 at 08:03
0

This is seems problem in ios10

it can be solved by overriding the controller method viewDidLayoutSubviews() or call method layoutIfNeeded() for the view which dimension value you might need before getting its dimension. Objective-C :[viewObject layoutIfNeeded] Swift: viewObject.layoutIfNeeded()

if the dimension value is still not correct then use layoutIfNeeded method for the parent view of the view object.

KGen
  • 50
  • 3