简体   繁体   中英

Repositioning controls when the orientation changes

I know Auto Layout can be used to make the sizes and position consistent when the orientation changes. Is it possible to completely change the layout when the orientation changes?

For example, please look at the below wire-frame of a simple login screen in portrait mode.

在此输入图像描述

Now if I rotate the device, I want to completely re-position the controls.

在此输入图像描述

Can this kind of a thing be done by using Auto Layout? If not, how should I go about this?

Thank you.

In your case it can be achieved by two methods, instead of reframing every component you can group the controls like the following..

  1. Parent View -> User Info View -> All User Info controls.. By doing this you will have to just reframe the User Info View not all the controls..

    Then only Logo and Company name left to reframe.. Total 3 controls to reframe if you group your controls..

  2. Create two views one for Portrait and other for Landscape mode, and just add and remove on rotations.. this is the fastest way as you won't have to readjust the frame by tedious code.

Hope above helps.

you cant set frames differently : -

-(void)setFramesForPotrait
{

// set frames here

}

-(void)setFramesForLandscaeMode
{

// set frames here

}

-(bool)shouldAutorotate.....
{
return Yes
}

-()willAutoRotate......
{
if(orientation = uiinterfaceOrientationPotrait)
{
[self setFramesForPotrait];
}
else
{
[self setFramesForLandscape];
}

I've had the same problem and here's what I've found so far. The approach I'm using is having two sets (potentially multiple) sets of constraints for different screen sizes or orientations. So I just design for portrait and connect all constraints that are portrait-specific to a IBOutletCollection: 在此输入图像描述 Then switch the VC orientation in InterfaceBuilder to Landscape and add the required constraints for this orientation and connect to the corresponding outlet: 在此输入图像描述

Then in code I'm removing or adding the constraints as required:

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    [self updateViewConstraints];
}

- (void)updateViewConstraints
{
    [super updateViewConstraints];
    if (self.view.frame.size.width >= kSize * 2 + kPadding * 3)
    {
        [self.view removeConstraints:self.constraintsForPortrait];
        [self.view addConstraints:self.constraintsForLandscape];
    } else
    {
        [self.view removeConstraints:self.constraintsForLandscape];
        [self.view addConstraints:self.constraintsForPortrait];
    }
}

You can achieve similar results with this code, basing your adding/removing of constraints on orientation instead of frame size:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self updateViewConstraints];
}

But keeping in mind that Apple is rumored to release devices with different screen aspect ratios and obsoleting the UIInterfaceOrientation and rotation events, it might be worth preparing in advance. Will see what future brings.

The downside of the approach is that that Xcode will be complaining about the design being ambiguous, which it actually is, since Xcode doesn't know we'll be removing the ambiguity at runtime. To tackle that you could set the priority of the constraints to be optional for all other orientations that you're not designing for at this particular moment (eg if you're designing for Portrait then optionalize the constraints for Landscape).

When using autolayout you can override updateViewConstraints to modify the layout on orientation change:

- (void)updateViewConstraints{

  [super updateViewConstraints];
  //portrait
  if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation)){

  }
  //landscape
  else{
    //
  }
}

It can be done with layout constraints something like I have below. This doesn't quite work, because your sketch doesn't quite work -- your landscape view is too long compared with what you really get in landscape. You would have to shorten the login text fields for everything to fit, but this should give you an idea how it's done. The buttonWidth constraint shows how to have a negative correlation between the width of the view and the width of a button -- that is, the button's width will be less in landscape than in portrait. I have several IBOutlets to constraints that I reference in the code. I can describe them for you if you're interested, but I'll just throw this out there for now:

@implementation ViewController {
    IBOutlet NSLayoutConstraint *buttonWidth;
    IBOutlet NSLayoutConstraint *logoTop;
    IBOutlet NSLayoutConstraint *logoAlignToLabel;
    IBOutlet NSLayoutConstraint *logoSpaceToLabel;
    IBOutlet NSLayoutConstraint *coNameToButtonAlignment;
    IBOutlet UIButton *b;
    IBOutlet UIImageView *logo;
    IBOutlet UILabel *coName;
    NSLayoutConstraint *con2;
    NSArray *cons1;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [b removeConstraint:buttonWidth];
    buttonWidth = [NSLayoutConstraint constraintWithItem:b attribute:NSLayoutAttributeWidth relatedBy:0 toItem:self.view attribute:NSLayoutAttributeWidth multiplier:-.2193 constant:350];
    [self.view addConstraint:buttonWidth];
    [self.view layoutSubviews];
}

- (void)updateViewConstraints{
    [super updateViewConstraints];
    if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation)){
        if (con2 != nil) {
            [self.view removeConstraints:cons1];
            [self.view removeConstraint:con2];
            [self.view addConstraints:@[logoAlignToLabel,logoSpaceToLabel,logoTop,coNameToButtonAlignment]];
        }
    }else{
        NSLog(@"Landscape");
        [self.view removeConstraints:@[logoAlignToLabel,logoSpaceToLabel,logoTop,coNameToButtonAlignment]];
        cons1 = [NSLayoutConstraint constraintsWithVisualFormat:@"|-8-[logo]-4-[coName]" options:NSLayoutFormatAlignAllCenterY metrics:0 views:@{@"logo":logo, @"coName":coName}];
        con2 = [NSLayoutConstraint constraintWithItem:logo attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
        [self.view addConstraints:cons1];
        [self.view addConstraint:con2];
    }
}

On rotation the logo and company name label have their constraints removed, and new ones put in place. The new constraint for the button, that I put on in viewDidLoad, takes care of rotation automatically, so I don't have to adjust it at all during the rotation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM