旋转设备后,UIViews会正确更新.我正在计算他们的框架尺寸和起源.但是,标签不会保持居中,并且不遵守故事板中定义的约束.
以下是显示问题的屏幕截图.如果我注释掉viewDidLayoutSubviews方法,标签完全居中(但是UIViews的大小不正确).我意识到我可以手动调整每个标签的框架,但我正在寻找一种方法,让他们在新调整大小的超级视图中尊重他们的约束.
这是代码:
#import "ViewController.h" @interface ViewController () @property (nonatomic) CGFloat spacer; @end @implementation ViewController @synthesize topLeftView,bottomRightView,topLeftLabel,bottomRightLabel; - (void)viewDidLoad { [super viewDidLoad]; topLeftLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; bottomRightLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; self.spacer = 8.0f; } - (void)viewDidLayoutSubviews { if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) { [self setupTopLeftForLandscape]; [self setupBottomRightForLandscape]; } else { [self setupTopLeftForPortrait]; [self setupBottomRightForPortrait]; } } - (void) setupTopLeftForPortrait { CGRect frame = topLeftView.frame; frame.origin.x = self.spacer; frame.origin.y = self.spacer; frame.size.width = self.view.frame.size.width - 2*self.spacer; frame.size.height = (self.view.frame.size.height - 3*self.spacer) * 0.5; [topLeftView setFrame:frame]; } - (void) setupBottomRightForPortrait { CGRect frame = bottomRightView.frame; frame.origin.x = self.spacer; frame.origin.y = topLeftView.frame.size.height + 2*self.spacer; frame.size.width = topLeftView.frame.size.width; frame.size.height = topLeftView.frame.size.height; [bottomRightView setFrame:frame]; } - (void) setupTopLeftForLandscape { CGRect frame = topLeftView.frame; frame.origin.x = self.spacer; frame.origin.y = self.spacer; frame.size.width = (self.view.frame.size.width - 3*self.spacer) * 0.5; frame.size.height = self.view.frame.size.height - 2*self.spacer; [topLeftView setFrame:frame]; } - (void) setupBottomRightForLandscape { CGRect frame = bottomRightView.frame; frame.origin.x = self.topLeftView.frame.size.width + 2*self.spacer; frame.origin.y = self.spacer; frame.size.width = topLeftView.frame.size.width; frame.size.height = topLeftView.frame.size.height; [bottomRightView setFrame:frame]; } @end
另一个经验法则是在约束系统之前计算setFrame和传统布局树.这可能看起来与第一部分相反,但请记住1)在传统的布局树中,视图布置了它们的子视图,然后在它们上面调用layoutSubviews,因此每个人的超级视图框架在它自己放置之前设置但是2)在约束系统,它试图从子视图,自下而上计算超视图帧.但在获取信息后,每个子视图报告信息,布局工作自上而下完成.
定影
那你离开了哪里?你是正确的,你需要以编程方式设置它.在IB中没有办法表明你应该从上到下切换到左右.这是你如何做到这一点:
>选择一个旋转并确保设置所有约束
您在“界面”构建器中所需的方式 – 例如,每个颜色
视图从superview中提取8点(你的间隔视图). “明确约束”和
底部的“更新框架”按钮将帮助您,您将需要单击
它通常是为了确保它是同步的.
>非常重要的是,左上角的视图只能连接到
左侧(前方)和上方以及右下方的超视图
仅由右侧(尾部)和底部连接.如果你清楚
设置高度和宽度固定的尺寸,这将产生一个
警告.这是正常的,在这种情况下可以通过设置来解决
“相等宽度”和“相等高度”,如果需要,还可以是步骤3的一部分.
(注意,常量必须为零才能使值真正相等.)
在其他情况下,我们必须设置一个约束并将其标记为“占位符”
沉默编译器,如果我们确定我们将填充信息,但编译器不知道.
>识别(或创建)链接右/底部的两个约束
查看左侧和顶部的内容.您可能希望使用IB左侧的对象浏览器.在中创建两个出口
viewController.h使用助手编辑器.看起来像:
@property(弱,非原子)IBOutlet NSLayoutConstraint * bottomViewToTopConstraint;
@property(弱,非原子)IBOutlet NSLayoutConstraint * rightViewToLeftConstraint;
>在viewController中实现updateConstraints.这是哪里的
逻辑将去:
.
-(void)updateViewConstraints { //first remove the constraints [self.view removeConstraints:@[self.rightViewToLeftConstraint,self.bottomViewToTopConstraint]]; if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) { //align the tops equal self.bottomViewToTopConstraint = [NSLayoutConstraint constraintWithItem:self.bottomRightView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLeftView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]; //align to the trailing edge by spacer self.rightViewToLeftConstraint = [NSLayoutConstraint constraintWithItem:self.bottomRightView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.topLeftView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:self.spacer]; } else { //portrait //right view atached vertically to the bottom of topLeftView by spacer self.bottomViewToTopConstraint = [NSLayoutConstraint constraintWithItem:self.bottomRightView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.topLeftView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:self.spacer]; //bottom view left edge aligned to left edge of top view self.rightViewToLeftConstraint = [NSLayoutConstraint constraintWithItem:self.bottomRightView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.topLeftView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0]; } [self.view addConstraints:@[self.rightViewToLeftConstraint,self.bottomViewToTopConstraint]]; [super updateViewConstraints];
}
由于在添加约束后不能更改约束(常量除外),我们必须执行此删除 – 添加步骤.注意IB中的那些也可能是占位符,因为我们每次都删除它们(我们可以先检查).我们可以将常量修改为某个偏移值,例如通过spacer topViewHight spacer与superview相关.但这意味着当自动布局计算此视图时,您已根据其他可能已更改的信息做出假设.交换视图并更改它们相关的因素,这些因素旨在相互关联.
请注意,因为Auto Layout将在传递信息时使用约束,所以首先我们修改它们,然后我们调用super.这是调用超类私有实现来为此视图进行计算,而不是视图层次结构中此视图的超级视图,尽管事实上下一步将在树的更上一层.