1

Consider the following UIView "MainView":

enter image description here

The view includes a Container View which in turn houses a UITableView controller. The container view's y coordinate starts just beneath the gradient bar. The UITableView includes the section footer at very bottom with the 'STU' label and 'chart' button.

When the UIView loads, and up-to-and-until any interaction with the tableView, MainView's dimensions are:

Frame: 0.000000x, 0.000000y, 568.000000w, 268.000000h

I have a delegate protocol set up such that tapping the chart button in the tableView will create a new view in MainView for a shadow effect via a method performing:

CGRect newFrame = self.view.frame; // self = MainView
newFrame.size.width = 100;
newFrame.size.height = 50;
UIView *backgroundShadowView = [[UIView alloc] initWithFrame:newFrame];
backgroundShadowView.backgroundColor = [UIColor blackColor];
// Do Animation

The important part above is the 'newFrame' CGRect. For some reason after interacting with the table view by tapping the chart button, or even scrolling or tapping a row, self.view.frame suddenly has the following dimensions:

Frame: 0.000000x, 52.000000y, 568.000000w, 268.000000h

And so the shadow view appears as follows, with a y origin much farther down than where it would be expected to start, just above the gradient bar.

enter image description here

I've adjusted the width and height of the "shadowview" for this question; normally it would be 568x268, but would extend 52 units off screen on the bottom because of this issue.

52 units is exactly the height of the statusbar (20) + navigationbar_in_landscape (32).

Of course I could manually adjust the frame dimensions, but I do not want to. I want to know why the view's frame is changing unexpectedly.

For the life of me, I cannot figure out why the view becomes suddenly offset. Any help is appreciated!!

OneManBand
  • 528
  • 5
  • 24

1 Answers1

1

Two comments.

(1)

This code was probably always wrong:

CGRect newFrame = self.view.frame; // self = MainView
newFrame.size.width = 100;
newFrame.size.height = 50;
UIView *backgroundShadowView = [[UIView alloc] initWithFrame:newFrame];

You surely want to define backgroundShadowView's frame in terms of self.view's bounds, not its frame as you are doing in the first line here.

(2)

The change in self.view.frame is probably illusory. You are probably checking this initially in viewDidLoad. But that is too soon; the view has not yet been added to the interface, and so it has not yet been resized to fit the surroundings.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Coincidentally I just found this post http://stackoverflow.com/a/21793477/2418006 describing much the same thing. Still, I don't quite understand how bounds is giving any useful information - won't bounds' x and y origins always be 0 since its a coordinate system relative to itself? This method almost seems the equivalent of manually setting these values to 0, but "it feels better" to do so with bounds since its a property of the parent object :X – OneManBand May 14 '14 at 16:13
  • Good call @ your second comment, seems obvious now >. – OneManBand May 14 '14 at 16:18
  • @OneManBand you didn't show enough code for me to be sure, which is why I hedged my answer - it depends what you are _doing_ with `backgroundShadowView`. But if you are making it a subview of `self.view` then I am right, because `backgroundShadowView.frame` is in `self.view.bounds` coordinate system. – matt May 14 '14 at 16:27
  • 1
    @OneManBand In other words you must _never_ set a subview's frame in terms of its superview's _frame_; you must _always_ set it in terms of its superview's _bounds_. See my discussion of frame and bounds starting here: http://www.apeth.com/iOSBook/ch14.html#_frame – matt May 14 '14 at 16:31