ios – 超视图帧尺寸更改后更新约束

我有一个非常简单的UIViewController,我正在尝试更好地理解约束,自动布局和框架.视图控制器有两个子视图:两个都是UIViews,它们可以并排放置,也可以根据设备方向并排放置在顶部/底部.在每个UIView中,存在一个应该在其superview中居中的单个标签.

旋转设备后,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中获取任何信息.

另一个经验法则是在约束系统之前计算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.这是调用超类私有实现来为此视图进行计算,而不是视图层次结构中此视图的超级视图,尽管事实上下一步将在树的更上一层.

以上是来客网为你收集整理的ios – 超视图帧尺寸更改后更新约束全部内容,希望文章能够帮你解决ios – 超视图帧尺寸更改后更新约束所遇到的程序开发问题。

如果觉得来客网网站内容还不错,欢迎将来客网网站推荐给程序员好友。