简体   繁体   English

方向改变时重新定位控件

[英]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.. 然后只剩下徽标和公司名称进行重新设定..如果您对控件进行分组,则需要重新设置3个控件。

  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: 所以我只是为肖像设计并将所有特定于肖像的约束连接到IBOutletCollection: 在此输入图像描述 Then switch the VC orientation in InterfaceBuilder to Landscape and add the required constraints for this orientation and connect to the corresponding outlet: 然后将InterfaceBuilder中的VC方向切换为横向,并为此方向添加所需的约束并连接到相应的插座: 在此输入图像描述

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. 但请记住,传闻苹果公司会发布具有不同屏幕宽高比的设备并废弃UIInterfaceOrientation和旋转事件,因此可能需要提前做好准备。 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. 这种方法的缺点是,Xcode会抱怨设计是模糊的,实际上是,因为Xcode不知道我们将在运行时消除歧义。 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). 为了解决这个问题,您可以将约束的优先级设置为您在此特定时刻未设计的所有其他方向的可选项(例如,如果您正在设计Portrait,则可以选择Landscape的约束)。

When using autolayout you can override updateViewConstraints to modify the layout on orientation change: 使用autolayout时,您可以覆盖updateViewConstraints以修改方向更改时的布局:

- (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. buttonWidth约束显示如何在视图宽度和按钮宽度之间建立负相关 - 也就是说,按钮的宽度在横向上比在纵向中要小。 I have several IBOutlets to constraints that I reference in the code. 我有几个IBOutlet来约束我在代码中引用的约束。 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. 我在viewDidLoad中放置的按钮的新约束会自动处理旋转,所以在旋转期间我根本不需要调整它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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