我可以使用自动布局为横向和纵向提供不同的约束吗?
设备旋转时是否可以更改约束条件? 这可能如何实现?
一个简单的例子可能是两个图像,纵向堆叠,而在横向上并排。
如果这是不可能的,我怎么可以完成这个布局?
我在代码中构build我的视图和约束,而不是使用接口生成器。
编辑:使用Xcode 6中引入的大小类的新概念,您可以轻松地在Interface Builder中为特定大小类设置不同的约束。 大多数设备(例如所有当前的iPhone)在横向模式下具有紧凑的垂直尺寸类别。
对于总体布局决定来说,这是一个比确定设备方向更好的概念。
这就是说,如果你真的需要知道方向, UIDevice.currentDevice().orientation
是要走的路。
原文:
覆盖UIViewController
的updateViewConstraints
方法,为特定情况提供布局约束。 这样,布局总是根据情况正确设置。 确保它们与故事板中创build的那些约束形成一套完整的约束。 您可以使用IB来设置您的一般约束,并将需要更改的对象标记为在运行时删除。
我使用以下实现为每个方向呈现一组不同的约束:
-(void)updateViewConstraints { [super updateViewConstraints]; // constraints for portrait orientation // use a property to change a constraint's constant and/or create constraints programmatically, eg: if (!self.layoutConstraintsPortrait) { UIView *image1 = self.image1; UIView *image2 = self.image2; self.layoutConstraintsPortrait = [[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy]; [self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem: image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]]; [self.layoutConstraintsPortrait addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]]; } // constraints for landscape orientation // make sure they don't conflict with and complement the existing constraints if (!self.layoutConstraintsLandscape) { UIView *image1 = self.image1; UIView *image2 = self.image2; self.layoutConstraintsLandscape = [[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[image1]-[image2]-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(image1, image2)] mutableCopy]; [self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:image1.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]]; [self.layoutConstraintsLandscape addObject:[NSLayoutConstraint constraintWithItem:image2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem: image2.superview attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]]; } BOOL isPortrait = UIInterfaceOrientationIsPortrait(self.interfaceOrientation); [self.view removeConstraints:isPortrait ? self.layoutConstraintsLandscape : self.layoutConstraintsPortrait]; [self.view addConstraints:isPortrait ? self.layoutConstraintsPortrait : self.layoutConstraintsLandscape]; }
现在,您只需要在情况发生变化时触发约束更新。 覆盖willAnimateRotationToInterfaceOrientation:duration:
在定向更改上animation约束更新:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; [self.view setNeedsUpdateConstraints]; }
我使用的方法(好或坏)是在故事板编辑器中定义两组约束(纵向和横向)。
为了避免地狱的故事板警告,我把所有的一组优先级设置为999,所以它不会在任何地方显示红色。
然后,我将所有约束添加到出口集合:
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *portraitConstraints; @property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *landscapeConstraints;
最后,我实现了ViewControllers
的viewWillLayout
方法:
- (void) viewWillLayoutSubviews { [super viewWillLayoutSubviews]; for (NSLayoutConstraint *constraint in self.portraitConstraints) { constraint.active = (UIApplication.sharedApplication.statusBarOrientation == UIDeviceOrientationPortrait); } for (NSLayoutConstraint *constraint in self.landscapeConstraints) { constraint.active = (UIApplication.sharedApplication.statusBarOrientation != UIDeviceOrientationPortrait); } }
这似乎工作。 我真的希望你可以在故事板编辑器中设置默认的活动属性。
我遵循与你一样的方法(没有nib文件或故事板)。 你必须更新你的约束updateViewConstraints
方法(通过检查设备的方向)。 无需在updateViewConstraints
调用setNeedsUpdateConstraints
,因为只要更改设备方向,就会自动调用最后一个方法。
您可以将您的约束保存到属性或variables中,然后将其设置为纵向和横向版本,并在旋转时将其移除。
我已经完成了这个约束,在xib初始视图中,将它们分配给视图控制器中的sockets。 在旋转时,我创build替代限制,删除sockets,但保留它们,插入替代品。
反向旋转过程。
我的想法是通过改变约束优先级来处理方向。
假设优先事项是:
- 景观:910活跃/ 10不活跃。
- 肖像:920有效/ 20无效。
步骤1:在带有约束的情节提要中创build横向(或纵向)devise。
步骤2:对于约束条件,只有横向模式设置优先级为10时,该条件才是有效的。
第3步:为肖像模式添加约束,并将其优先级设置为920。
在willAnimateRotationToInterfaceOrientation
添加代码:
for (NSLayoutConstraint *constraint in myView.constraints) { if (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) { if (constraint.priority == 10) constraint.priority = 910; if (constraint.priority == 920) constraint.priority = 20; } else { if (constraint.priority == 20) constraint.priority = 920; if (constraint.priority == 910) constraint.priority = 10; } }
这种方法的优点 – 在Interface Builder中轻松调整。 当我们需要切换到任何方向时,我们按优先级select所有约束,并同时改变它们(910-> 10,20-> 920):
界面将自动重build。