以编程方式使用自动布局实现带有子视图的 uiview 子类

Posted

技术标签:

【中文标题】以编程方式使用自动布局实现带有子视图的 uiview 子类【英文标题】:Implementing an uiview subclass with children views using autolayout programmatically 【发布时间】:2015-05-25 11:11:55 【问题描述】:

我的需求非常普遍,我必须实现一个 UIView 子类,该子类将一个 UIImageView 分组,在屏幕上以 x 为中心,距离顶部 20 点,以及一个带有描述的 UILabel。 我使用界面生成器没有问题,但由于我需要以编程方式制作它,因此我关注了技术和最佳实践。 到目前为止,我想出了这段代码,开始只可视化图像。尽管它非常基本,但我无法理解为什么视图没有派生(如您从屏幕截图中看到的那样)正确的框架,该框架应该从图像视图的所有边缘“偏移”20 个点。

这是我的子类:

标题

@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 子类的代码的 sn-p:

    - (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 点,但结果完全不同,我没有任何调试器日志或不一致之处,显然我必须遗漏一些非常基本的东西,但所以到目前为止我不明白什么。

【问题讨论】:

【参考方案1】:

常量描述 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 的后沿放置 20 个点到红色 View 的左侧 (-X 20)

将红色 View 的底部放置在 imageView 下方 (+Y 20) 20 点处 将红色 View 的尾部边缘放置在 imageView 的右侧 (+X 20) 处 20 点

【讨论】:

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

以上是关于以编程方式使用自动布局实现带有子视图的 uiview 子类的主要内容,如果未能解决你的问题,请参考以下文章

以编程方式使用自动布局约束在视图中垂直对齐中间的子视图

在 UIScrollView 子视图中使用自动布局(以编程方式)

我们可以将具有自动布局的 XIB 加载为以编程方式创建的没有自动布局的视图的子视图,并使用父视图调整子视图的大小吗?

以编程方式使用自动布局将子视图添加到 UICollectionView 不起作用

以编程方式将自动布局约束添加到恒定宽度和高度的子视图

使用自动布局的屏幕外 UIView(以编程方式)