Question

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.

Was it helpful?

Solution

Moving your buttons shouldn't result in the modification of the "tappable" area of your button. The only reason that I can think that would cause something like this to occur are:

  1. You have a transparent view covering parts of your buttons after rotation. If you do have transparent views, make their background color red and see what happens after rotation.

  2. If your buttons aren't children of the main view, turn on the "Clips Subviews" setting in the xib file or turn on the clipsToBounds property in code of the parent view of the button. If your buttons are clipped during rotation, this could be another reason for your issue.

Let me know if any of this helps.

OTHER TIPS

This is not really an explanation for why you are getting that behavior but you will probably have better luck subclassing UIView, putting the layout code in there, and then using the UIView subclass in your view controller. I animate buttons a quite a bit in my own app and subclassing UIView has led to the smallest amount of head scratching with regard to rotation.

… Your viewButtons.origin.y issue may be related to how you get the screen dimensions. Maybe. Try this

UIView *rootView = [[[UIApplication sharedApplication] keyWindow] 
                                   rootViewController].view;
CGRect originalFrame = [[UIScreen mainScreen] bounds];
CGRect adjustedFrame = [rootView convertRect:originalFrame fromView:nil];
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top