Ios 使用autolayout以编程方式实现带有子视图的uiview子类

Ios 使用autolayout以编程方式实现带有子视图的uiview子类,ios,objective-c,uiview,autolayout,nslayoutconstraint,Ios,Objective C,Uiview,Autolayout,Nslayoutconstraint,我的需求是非常通用的,我必须实现一个UIView子类,它将一个UIImageView、一个在屏幕上以x为中心、距离顶部20点的UILabel和一个带有描述的UILabel分组。 我用interface builder做这件事没有问题,但因为我需要以编程方式来做,所以我关注技术和最佳实践。 到目前为止,我提出了这段代码,开始将图像可视化。尽管它是非常基本的,但我无法理解为什么视图不能导出(从屏幕截图中可以看到)正确的帧,该帧应该在图像视图的所有边缘上“偏移”20个点 下面是我的子类: -

我的需求是非常通用的,我必须实现一个UIView子类,它将一个UIImageView、一个在屏幕上以x为中心、距离顶部20点的UILabel和一个带有描述的UILabel分组。
我用interface builder做这件事没有问题,但因为我需要以编程方式来做,所以我关注技术和最佳实践。 到目前为止,我提出了这段代码,开始将图像可视化。尽管它是非常基本的,但我无法理解为什么视图不能导出(从屏幕截图中可以看到)正确的帧,该帧应该在图像视图的所有边缘上“偏移”20个点

下面是我的子类:

    - (void)viewDidLoad {
    [super viewDidLoad];

    ProgrammaticAutolayoutView *test = [[ProgrammaticAutolayoutView alloc] init];
    [test setTranslatesAutoresizingMaskIntoConstraints:NO];
    test.imageView.image = [UIImage imageNamed:@"dmy"];
    test.backgroundColor = [UIColor redColor];

    [self.view addSubview: test];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem: test attribute:NSLayoutAttributeCenterX relatedBy: NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem: test attribute:NSLayoutAttributeCenterY relatedBy: NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];

    [test setNeedsLayout];
    [test layoutIfNeeded];
}
标题

@interface ProgrammaticAutolayoutView : UIView

@property (nonatomic, strong) UIImageView *imageView;

@end
实施

#import "ProgrammaticAutolayoutView.h"

@implementation ProgrammaticAutolayoutView{

    BOOL _didUpdateConstraints;
}

- (instancetype)init
{
    return [self initWithFrame:CGRectZero];;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

        _didUpdateConstraints = NO;

        _imageView = [UIImageView new];
        [_imageView setTranslatesAutoresizingMaskIntoConstraints: NO];

        [self addSubview: _imageView];
    }
    return self;
}

- (void) updateConstraints{

    if(!_didUpdateConstraints){
        [self setupConstraints];
    }

    [super updateConstraints];
}

- (void) setupConstraints{

    [self.imageView addConstraint:[NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:50]];

    [self.imageView addConstraint:[NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:50]];

    [self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:20.0]];

    [self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:20.0]];

    [self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:20.0]];

    [self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:20.0]];

    _didUpdateConstraints = YES;
}

@end
这是我用来实例化和绘制uiview子类的代码片段:

    - (void)viewDidLoad {
    [super viewDidLoad];

    ProgrammaticAutolayoutView *test = [[ProgrammaticAutolayoutView alloc] init];
    [test setTranslatesAutoresizingMaskIntoConstraints:NO];
    test.imageView.image = [UIImage imageNamed:@"dmy"];
    test.backgroundColor = [UIColor redColor];

    [self.view addSubview: test];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem: test attribute:NSLayoutAttributeCenterX relatedBy: NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem: test attribute:NSLayoutAttributeCenterY relatedBy: NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];

    [test setNeedsLayout];
    [test layoutIfNeeded];
}
我本来希望看到的子视图与uiimageview所有边缘的偏移量为20点,但结果完全不同,我没有调试器日志或任何不一致之处,显然我肯定缺少一些非常基本的内容,但到目前为止我不明白是什么


常数描述X和Y偏移。你的4个约束条件是:

  • 将imageView顶部置于红色视图(+Y 20)下方20点处
  • 将imageView底部置于红色视图(+Y 20)下方20点处
  • 将imageView的前缘20点置于红色视图的右侧(+X 20)
  • 将imageView的后缘20点置于红色视图的右侧(+X 20)
这就是你的照片所显示的

要使红色框成为图像的边框,可以将两个常量设置为负数:

[self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:20.0]];

[self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-20.0]];

[self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:20.0]];

[self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:-20.0]];
切换底部和尾部约束中项目的顺序:

[self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:20.0]];

[self addConstraint:[NSLayoutConstraint constraintWithItem: self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:20.0]];

[self addConstraint:[NSLayoutConstraint constraintWithItem: self.imageView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:20.0]];

[self addConstraint:[NSLayoutConstraint constraintWithItem: self attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.imageView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:20.0]];

新建议的限制条件是:

  • 将imageView的底部置于红色视图(-Y 20)上方20点处
  • 将imageView的后缘放置在红色视图的左侧(-X 20)处

  • 将红色视图的底部放置在图像视图(+Y 20)下方20点处
  • 将红色视图的后缘放置在imageView的右侧(+X 20)20点处

负值……就这么明显吗?谢谢你的回答,这很明显,但对我来说不是很明显!不客气。Interface Builder经常切换项目的顺序(这很微妙)。这就是为什么你不经常在IB中看到负值的原因。它们当然具有相同的效果。