I'm having trouble with a couple of buttons after rotation. When in portrait mode, the buttons are stacked at the bottom of the screen. When in landscape, they are moved and resized to be side-by-side at the bottom of the screen. This all works great and the buttons behave correctly. However, if the phone is then rotated back to portrait, the buttons' tap area is wrong - only the left 1/3 of the buttons is tappable.
Here's the code that does the rotation. (I call it within viewWillAppear as well, so it always gets executed when the view is shown, in case the view is already in landscape.) I've put the buttons in their own inner view.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration {
// determine our dimensions based on orientation
CGRect mainRect = [[UIScreen mainScreen] bounds];
CGFloat maxWidthHeight = MAX(mainRect.size.width, mainRect.size.height);
CGFloat minWidthHeight = MIN(mainRect.size.width, mainRect.size.height);
CGFloat _windowWidth = (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) ? minWidthHeight : maxWidthHeight;
// get the current sizes of the things we are moving
CGRect saveRect = self.viewButtons.frame;
CGRect addLocRect = self.buttonAddLocation.frame;
CGRect connectRect = self.buttonConnect.frame;
// This will be set below in one of the if-else branches
CGFloat buttonWidth = 0;
// determine the offset from the left/right based on device and orientation
int offset = 0;
if ([self isIphone]) {
offset = (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) ? OFFSET_LEFT_PORTRAIT_IPHONE : OFFSET_LEFT_LANDSCAPE_IPHONE;
} else {
offset = (UIDeviceOrientationIsPortrait(toInterfaceOrientation)) ? OFFSET_LEFT_PORTRAIT_IPAD : OFFSET_LEFT_LANDSCAPE_IPAD;
}
// change the size & location of the button frame to just the button height to maximize the area for the location list
// no matter what orientation, the button frame will fill the bottom of the screen
saveRect.size.width = _windowWidth - 2*offset;
saveRect.origin.x = offset;
// for Landscape, move the buttons to side-by-side at the bottom of the window
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
// size & move the buttons to fit side-by-side
buttonWidth = (saveRect.size.width)*.4;
addLocRect.origin.x += offset;
addLocRect.origin.y = saveRect.size.height - addLocRect.size.height ;
connectRect.origin.x = saveRect.size.width - buttonWidth - offset;
connectRect.origin.y = saveRect.size.height - connectRect.size.height;
} else { // Portrait
// move the buttons down to the bottom of the frame, stacked
// size the buttons to be fully across the screen
buttonWidth = saveRect.size.width;
addLocRect.origin.y = 0 ; // at the top of the button view
addLocRect.origin.x = 0;
connectRect.origin.y = saveRect.size.height - connectRect.size.height;
connectRect.origin.x = 0;
}
connectRect.size.width = buttonWidth;
addLocRect.size.width = buttonWidth;
self.buttonAddLocation.frame = addLocRect;
self.buttonConnect.frame = connectRect;
self.viewButtons.frame = saveRect;
}
I added some logging to determine what's going on with the frames and bounds at the end of the rotation:
NSLog(@"Post rotation:");
NSLog(@"AddLocation bounds: w=%f, h=%f, x=%f, y=%f", self.buttonAddLocation.frame.size.width, self.buttonAddLocation.frame.size.height,
self.buttonAddLocation.frame.origin.x, self.buttonAddLocation.frame.origin.y);
NSLog(@"AddLocation frame: w=%f, h=%f, x=%f, y=%f", self.buttonAddLocation.bounds.size.width, self.buttonAddLocation.bounds.size.height,
self.buttonAddLocation.bounds.origin.x, self.buttonAddLocation.bounds.origin.y);
NSLog(@"viewButtons bounds: w=%f, h=%f, x=%f, y=%f", self.viewButtons.frame.size.width, self.viewButtons.frame.size.height,
self.viewButtons.frame.origin.x, self.viewButtons.frame.origin.y);
NSLog(@"viewButtons frame: w=%f, h=%f, x=%f, y=%f", self.viewButtons.bounds.size.width, self.viewButtons.bounds.size.height,
self.viewButtons.bounds.origin.x, self.viewButtons.bounds.origin.y);
Which resulted in:
Post rotation: (NOTE: Portrait, initial appearance)
AddLocation bounds: w=272.000000, h=55.000000, x=0.000000, y=0.000000
AddLocation frame: w=272.000000, h=55.000000, x=0.000000, y=0.000000
viewButtons bounds: w=272.000000, h=120.000000, x=24.000000, y=374.000000
viewButtons frame: w=272.000000, h=120.000000, x=0.000000, y=374.000000
Post rotation: (NOTE: rotate to Landscape)
AddLocation bounds: w=217.600006, h=55.000000, x=12.000000, y=65.000000
AddLocation frame: w=217.600006, h=55.000000, x=0.000000, y=0.000000
viewButtons bounds: w=544.000000, h=120.000000, x=12.000000, y=374.000000
viewButtons frame: w=544.000000, h=120.000000, x=0.000000, y=374.000000
Post rotation: (NOTE: back to Portrait)
AddLocation bounds: w=272.000000, h=55.000000, x=0.000000, y=0.000000
AddLocation frame: w=272.000000, h=55.000000, x=0.000000, y=0.000000
viewButtons bounds: w=272.000000, h=120.000000, x=24.000000, y=138.000000
viewButtons frame: w=272.000000, h=120.000000, x=0.000000, y=374.000000
The only difference I see from the initial to final is the viewButtons bounds origin.y, but if I try setting that, things get messed up - the buttons suddenly appear at the top of the screen. The button bounds are wide enough.
What am I missing?
UPDATED: I was missing the fact that I'd set up struts and a spring in IB for the enclosing view, which was fighting with the code I had setting the frame of the view. I removed the code to set the frame, letting IB do the work, and fiddled with the offsets for the buttons. Not the prettiest solution, but I need to release it.