1

I have heard that viewDidLayoutSubviews is the best place to alter the layout when we have used constraints.

So I jumped to viewDidLayoutSubviews

I have created three UIViews and SubViewed them on SuperView. I am not mentioning the code for frame calculation.

 [self.view addSubview:imgMiddleCircle];
 [self.view addSubview:imgFirstCircle];
 [self.view addSubview:imgLastCircle]; 

Using this piece of I am adding these circles.

Now when I run my code In viewDidLayoutSubviews I get following screens:

enter image description here

And when I switch to viewWillLayoutSubviews I am getting this on screen:

enter image description here

Why I am getting extra two circles in viewDidLayoutSubviews even I am creating three circles.

And why in viewWillLayout gives the correct Output.

Lorenzo
  • 3,293
  • 4
  • 29
  • 56
Rahul
  • 5,594
  • 7
  • 38
  • 92
  • 1
    `viewDidLayoutSubviews` is called multiple times, that's why you see the extra views. So, it is _not_ the best place to add subviews. Typically you'd add the subviews in `viewDidLoad` and if you're really sure that you want to manually calculate the frames, do only that in `viewDidLayoutSubviews` – Alladinian Oct 15 '15 at 10:06
  • you mean Internally `viewDidLayoutSubviews` called multiple times.... And i can't use `viewDidLoad` as I have autolayout turned on. I am doing calculation based on existing controls..and In `viewDidLoad` I am not getting correct frame for existing controls – Rahul Oct 15 '15 at 10:09
  • 1
    @RahulMishra set the frame in `viewDidLayoutSubviews` and add subviews in `viewDidLoad` – Bhavin Bhadani Oct 15 '15 at 10:12
  • I am creating these views programatically ... – Rahul Oct 15 '15 at 10:23

2 Answers2

3

You should code for the fact that viewDidLayoutSubviews is called multiple types.

Ideally addSubview: should be happening in a place like viewDidLoad where you are sure it is only called once.

You can create a flag to avoid calling addSubview: multiples types (not my personal choice)

Otherwise, try to move your set up code to viewDidLoad and force the view to render itself before doing your calculation:

[yourView setNeedsLayout];

[yourView layoutIfNeeded];

Edgar
  • 2,500
  • 19
  • 31
2

Per Apple Documentation,

When the bounds change for a view controller's view, the view adjusts the positions of its subviews and then the system calls this method. However, this method being called does not indicate that the individual layouts of the view's subviews have been adjusted. Each subview is responsible for adjusting its own layout.

Your view controller can override this method to make changes after the view lays out its subviews. The default implementation of this method does nothing.

So, essentially, viewDidLayoutSubiews gets called multiple times during the creation of your viewController including in cases like rotating the device, scrolling etc. So, you should be really careful with the code you add to this method, because it might be executed multiple times as well. Use this method to reposition your sub-views and not to add/remove them.

Take a look at this blog for more details.

Abhinav
  • 37,684
  • 43
  • 191
  • 309
  • I want to add a sub layer to my view which has rounded corners. I added the rounded corner code in didLayoutsubviews which makes sense because my elements can change size and I need to adopt the corner radius based on that. Now I added the layer insertion code and because of multiple calls, multiple layers are added, what to do :(? – nr5 Jan 07 '20 at 14:03