Placing and Moving Views on Rotation (UIView)

2019-02-01 09:58发布

问题:

What's the "correct" way of exactly placing and moving views when an app rotates? That is, how can I have fine-grained control of the position, size, and reflow of my views when the UI rotates from portrait to landscape orientation (or vice-versa)? I think my two options are:

  1. Use two superviews (portrait and landscape). On rotation: toggle between them.
  2. Use one superview. On rotation: change each subview's frame, bounds, and center properties.

If you have two views with distinct enough layouts and elements, then the first way might be good enough. If your two views are essentially the same thing sized for different orientations, the second way is probably a better way to do it using only one view.

I suspect the former could be done with IB and the latter should be done programmatically.

回答1:

To have fine-grained control over the position and size of your subviews when the iPhone rotates, change the frame of the subviews in the UIViewController method willAnimateRotationToInterfaceOrientation:duration:. This method is called within an animation block, so all the changes to your subviews' frames that you make inside of it are animated.

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
        // Portrait frames
        self.subviewA.frame = CGRectMake(x, y, width, height);
        self.subviewB.frame = CGRectMake(x, y, width, height);
        self.subviewC.frame = CGRectMake(x, y, width, height);
    } else {
        // Landscape frames
        self.subviewA.frame = CGRectMake(x, y, width, height);
        self.subviewB.frame = CGRectMake(x, y, width, height);
        self.subviewC.frame = CGRectMake(x, y, width, height);
    }
}


回答2:

Here's one idea. I worry that the animations will work funny, but try it and see.

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toOrientation 
                                duration:(NSTimeInterval)duration {

    if (toOrientation == UIInterfaceOrientationLandscapeLeft ||
        toOrientation == UIInterfaceOrientationLandscapeRight) {
        [UIView beginAnimations:nil context:NULL]; {
            [UIView setAnimationDuration:1.0];
        }
            [UIView setAnimationDelegate:self];
        [viewA setFrame:CGRectMake(?,?,?,?)];
        [viewB setFrame:CGRectMake(?,?,?,?)];
        [viewC setFrame:CGRectMake(?,?,?,?)];
        } [UIView commitAnimations];    
    } else if  (toOrientation == UIInterfaceOrientationPortrait ||
            toOrientation == UIInterfaceOrientationPortraitUpsideDown) {
        [UIView beginAnimations:nil context:NULL]; {
            [UIView setAnimationDuration:1.0];
        }
        [UIView setAnimationDelegate:self];
        [viewA setFrame:CGRectMake(?,?,?,?)];
        [viewB setFrame:CGRectMake(?,?,?,?)];
        [viewC setFrame:CGRectMake(?,?,?,?)];
        } [UIView commitAnimations];    
    }


回答3:

I have an idea which is working properly for me where I am using a small view on a view where it rotates itself when orientation of device changes. Use one notifier then in the method change the orientation.

#define DegreesToRadians(x) (M_PI * x / 180.0)

.......

[[NSNotificationCenter defaultCenter] addObserver:showIndicator
                                         selector:@selector(setProperOreintation)
                                             name:UIDeviceOrientationDidChangeNotification
                                           object:nil];

.......

-(void)setProperOrientation {

UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3];


if (orientation == UIDeviceOrientationPortraitUpsideDown)
    self.transform = CGAffineTransformRotate(CGAffineTransformIdentity, DegreesToRadians(180)); 

else if (orientation == UIDeviceOrientationLandscapeLeft)
    self.transform = CGAffineTransformRotate(CGAffineTransformIdentity, DegreesToRadians(90));  

else if (orientation == UIDeviceOrientationLandscapeRight)
    self.transform = CGAffineTransformRotate(CGAffineTransformIdentity, DegreesToRadians(-90));

    [UIView commitAnimations]; }

Here instead of rotate u can use translate or scale



回答4:

There is a lot solutions for that. One of them is animations for controls as you read before. Another option is prepare 2 UIView one for portrait mode and another for landscape mode. And on switch orientation - load proper UIView. That's the way i used in my applications. Because sometimes differences between landscape and portrait is huge.

In simple cases is enough to set up correct autoresizingMask for subviews. Read about it. It works really nice.