以编程方式使用自动布局实现具有 children 视图的 uiview 子类
Implementing an uiview subclass with children views using autolayout programmatically
我的需求非常通用,我必须实现一个 UIView 子类,该子类将 UIImageView、x-centered 显示在屏幕上并距离顶部 20 pts,以及一个带有描述的 UILabel。
我在使用界面生成器时没有问题,但由于我需要以编程方式进行,所以我关注了技术和最佳实践。
到目前为止,我想出了这段代码,开始只可视化图像。尽管它非常基础,但我无法理解为什么视图没有派生(正如您从屏幕截图中看到的那样)正确的框架应该是图像视图所有边缘上的 "offsetted" 20 点。
这是我的子类:
header
@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 的顶部放在红色 View 下方 (+Y 20) 20 点
- 将 imageView 的底部放在红色 View 下方 (+Y 20) 20 点
- 将 imageView 的前沿放置在红色 View 的右侧 (+X 20) 20 点
- 将 imageView 的后缘放置在红色 View 的右侧 (+X 20) 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 的底部放在红色 View 上方 (-Y 20) 20 点
- 将 imageView 的后缘放在红色 View 的左侧 (-X 20) 20 点处
或
- 将红色View的底部放置在imageView下方20点(+Y 20)
- 将红色 View 的后缘放在 imageView 的右侧 (+X 20) 20 点
我的需求非常通用,我必须实现一个 UIView 子类,该子类将 UIImageView、x-centered 显示在屏幕上并距离顶部 20 pts,以及一个带有描述的 UILabel。
我在使用界面生成器时没有问题,但由于我需要以编程方式进行,所以我关注了技术和最佳实践。
到目前为止,我想出了这段代码,开始只可视化图像。尽管它非常基础,但我无法理解为什么视图没有派生(正如您从屏幕截图中看到的那样)正确的框架应该是图像视图所有边缘上的 "offsetted" 20 点。
这是我的子类:
header
@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 的顶部放在红色 View 下方 (+Y 20) 20 点
- 将 imageView 的底部放在红色 View 下方 (+Y 20) 20 点
- 将 imageView 的前沿放置在红色 View 的右侧 (+X 20) 20 点
- 将 imageView 的后缘放置在红色 View 的右侧 (+X 20) 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 的底部放在红色 View 上方 (-Y 20) 20 点
- 将 imageView 的后缘放在红色 View 的左侧 (-X 20) 20 点处
或
- 将红色View的底部放置在imageView下方20点(+Y 20)
- 将红色 View 的后缘放在 imageView 的右侧 (+X 20) 20 点