设备旋转时是否可以更改约束?怎么可能实现这一目标?
一个简单的例子可能是两个图像,它们在纵向上一个堆叠在另一个之上,但在景观中是并排的 .
如果这是不可能的,我怎么可能完成这个布局?
我正在构建代码中的视图和约束,而不是使用接口构建器 .
Edit: 使用Xcode 6中引入的新概念Size Classes,您可以轻松地在Interface Builder中为特定大小类设置不同的约束 . 大多数设备(例如所有当前的iPhone)在横向模式下具有紧凑的垂直尺寸等级 .
对于一般布局决策而言,这是一个比确定设备方向更好的概念 .
话虽这么说,如果你真的需要知道方向,那么 UIDevice.currentDevice().orientation 就是要走的路 .
UIDevice.currentDevice().orientation
Original post:
覆盖 UIViewController 的 updateViewConstraints 方法以提供特定情况的布局约束 . 这样,布局总是根据情况设置正确的方式 . 确保它们与故事板中创建的约束形成一组完整的约束 . 您可以使用IB来设置常规约束,并标记要在运行时删除的更改 .
UIViewController
updateViewConstraints
我使用以下实现为每个方向提供一组不同的约束:
-(void)updateViewConstraints { [super updateViewConstraints]; // constraints for portrait orientation // use a property to change a constraint's constant and/or create constraints programmatically, e.g.: 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: 以对方向更改的约束更新进行动画处理:
willAnimateRotationToInterfaceOrientation:duration:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration]; [self.view setNeedsUpdateConstraints]; }
我使用的方法(无论好坏)是在故事板编辑器中定义两组约束(纵向和横向) .
为了避免地狱的故事板警告,我将所有一组放在999的优先级,只是因为它不会显示任何地方的红色 .
然后我将所有约束添加到outlet集合:
@property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *portraitConstraints; @property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *landscapeConstraints;
最后,我实现了 ViewControllers 的 viewWillLayout 方法:
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); } }
这似乎有效 . 我希望你可以在storyboard编辑器中设置默认的活动属性 .
我遵循与您相同的方法(没有nib文件或故事板) . 您必须在 updateViewConstraints 方法中更新约束(通过检查设备方向) . 无需在 updateViewConstraints 中调用 setNeedsUpdateConstraints ,因为只要更改设备方向,就会自动调用最后一个方法 .
setNeedsUpdateConstraints
您可以将约束,属性或变量保存为纵向和横向版本,然后设置并在旋转时将其删除 .
我已经完成了这个,在xib中为初始视图制作了约束,将它们分配给视图控制器中的出口 . 在旋转时,我创建备用约束,移除出口但保留它们,插入备用 .
旋转后退反转过程 .
我的想法是通过改变约束优先级来处理方向 .假设优先事项是:
landscape:910 active / 10 inactive .
肖像:920有效/ 20无效 .
Step 1: 使用约束在Storyboard中创建横向(或纵向)设计 .Step 2: 对于约束,必须仅对横向模式激活,才能将优先级设置为10 .Step 3: 为纵向模式添加约束并将其优先级设置为920 .
在 willAnimateRotationToInterfaceOrientation 添加代码:
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中轻松调整 . 当我们需要切换到任何方向时,我们按优先级选择所有约束并同时更改它们(910-> 10,20-> 920):
界面将自动重建 .
5 回答
Edit: 使用Xcode 6中引入的新概念Size Classes,您可以轻松地在Interface Builder中为特定大小类设置不同的约束 . 大多数设备(例如所有当前的iPhone)在横向模式下具有紧凑的垂直尺寸等级 .
对于一般布局决策而言,这是一个比确定设备方向更好的概念 .
话虽这么说,如果你真的需要知道方向,那么
UIDevice.currentDevice().orientation
就是要走的路 .Original post:
覆盖
UIViewController
的updateViewConstraints
方法以提供特定情况的布局约束 . 这样,布局总是根据情况设置正确的方式 . 确保它们与故事板中创建的约束形成一组完整的约束 . 您可以使用IB来设置常规约束,并标记要在运行时删除的更改 .我使用以下实现为每个方向提供一组不同的约束:
现在,您需要做的就是在情况发生变化时触发约束更新 . 覆盖
willAnimateRotationToInterfaceOrientation:duration:
以对方向更改的约束更新进行动画处理:我使用的方法(无论好坏)是在故事板编辑器中定义两组约束(纵向和横向) .
为了避免地狱的故事板警告,我将所有一组放在999的优先级,只是因为它不会显示任何地方的红色 .
然后我将所有约束添加到outlet集合:
最后,我实现了
ViewControllers
的viewWillLayout
方法:这似乎有效 . 我希望你可以在storyboard编辑器中设置默认的活动属性 .
我遵循与您相同的方法(没有nib文件或故事板) . 您必须在
updateViewConstraints
方法中更新约束(通过检查设备方向) . 无需在updateViewConstraints
中调用setNeedsUpdateConstraints
,因为只要更改设备方向,就会自动调用最后一个方法 .您可以将约束,属性或变量保存为纵向和横向版本,然后设置并在旋转时将其删除 .
我已经完成了这个,在xib中为初始视图制作了约束,将它们分配给视图控制器中的出口 . 在旋转时,我创建备用约束,移除出口但保留它们,插入备用 .
旋转后退反转过程 .
我的想法是通过改变约束优先级来处理方向 .
假设优先事项是:
landscape:910 active / 10 inactive .
肖像:920有效/ 20无效 .
Step 1: 使用约束在Storyboard中创建横向(或纵向)设计 .
Step 2: 对于约束,必须仅对横向模式激活,才能将优先级设置为10 .
Step 3: 为纵向模式添加约束并将其优先级设置为920 .
在
willAnimateRotationToInterfaceOrientation
添加代码:这种方法的优点 - 在Interface Builder中轻松调整 . 当我们需要切换到任何方向时,我们按优先级选择所有约束并同时更改它们(910-> 10,20-> 920):
界面将自动重建 .