以编程方式在子类 UIView 的子视图上自动布局

Posted

技术标签:

【中文标题】以编程方式在子类 UIView 的子视图上自动布局【英文标题】:Autolayout programmatically on a subview of a subclassed UIView 【发布时间】:2012-11-20 16:54:39 【问题描述】:

我对 UIView 进行了子类化,以创建一个自定义 groupView,我可以使用它以一种简单的方式将一些东西添加到我的布局中。这个 groupView 包括一个用作标题的 UILabel 和一个在它的 CALayer 上绘制一个带有背景颜色的 roundRect 的 UIView。想想 UITableView 的部分。我通过删除 UIView 并将其类更改为我的子类来将此 groupView 添加到情节提要。一切正常,我通过 Xcode 中用户定义的运行时属性设置标题。一切都很好,我在情节提要的这个视图中添加了 UILabels,它在运行时创建了标题标签和圆形矩形。

我的 groupView 的结构:

    groupView: (UIView)clipToBounds:NO; 标题:(UILabel)定位 在 groupView 上方。 contentView:(UIView) 创建roundRect 通过 CALayer 和颜色,应该与 groupView 的大小相同。

那么问题是什么?好吧,开始处理自动布局是一件很痛苦的事情,但是要让这个子类 UIView 工作,我需要以编程方式设置 contentView 约束。我无法弄清楚这个自动布局 ASCII 格式字符串的语法。目前我有:

 _contentView = [[UIView alloc]initWithFrame:self.bounds];

    _contentView.layer.cornerRadius = 5.0f;
    _contentView.layer.masksToBounds=YES;
    _contentView.backgroundColor=_backgroundColor;
    _contentView.layer.borderWidth=_borderWidth;
    _contentView.layer.borderColor=_borderColor.CGColor;
    [self insertSubview:_contentView atIndex:0];
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(self,_contentView);
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"[self]-0-[_contentView]-0-[self]" options:0 metrics:nil views:viewsDictionary];

    for (NSLayoutConstraint *constraint in constraints) 
        [_contentView addConstraint:constraint];
    

哪个崩溃:* 由于未捕获的异常“NSGenericException”而终止应用程序,原因:“无法在视图上安装约束。约束是否引用了视图子树之外的内容?那是违法的。约束:视图:>'

我先试过了,还是不行:

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_contentView);
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-0-[_contentView]-0-|" options:0 metrics:nil views:viewsDictionary];

哪个崩溃:* 由于未捕获的异常“NSGenericException”而终止应用程序,原因:“无法在视图上安装约束。约束是否引用了视图子树之外的内容?那是违法的。约束:视图:>'

咆哮:不知何故,这个 AutoLayout 应该可以节省我们的工作,但是 我现在看不出好处是如何超过开销的。为什么 他们到底是不是从使用引用和方法甚至是类型 defs 到这个古老的格式字符串?这样做会容易得多: [_contentView 约束:NSLayoutFormatAlignLeading toView:self withDistance:0.0f];或者类似的东西?我宁愿交易 此时带有弹簧和支柱。

任何帮助理解或向我展示将 contentView 限制为 self 大小的语法都会有所帮助。

【问题讨论】:

关于您的咆哮:自动布局有一个学习曲线,一开始您确实倾向于讨厌它 - 但是一旦您完全考虑约束而不是框架,它就会变得更容易。而且“视觉格式”是毫无用处的,除非你只是把东西排成一排。另一种方法(constraintWithItem...)基本上是您在上面的咆哮中所使用的语法。 如果其他人在理解这个 ASCII-Art 格式字符串时遇到问题,我发现本教程很有帮助。我知道它适用于 Ruby,但格式字符串与 Objective-C 中的相同。 seanlilmateus.github.com 【参考方案1】:

错误告诉你你需要知道什么:

约束是否引用了视图子树之外的东西?

是的。它引用了它的超级视图。

您需要将这些约束应用于超级视图,在本例中为groupView

【讨论】:

好的,但这不是子视图的约束吗?这是我需要自动调整大小的子视图。我只是想错了吗? 这样想:它限制了contentViewgroupView 中的位置和大小。请参阅安装约束部分:developer.apple.com/library/mac/#documentation/UserExperience/… 好的,是的,我现在明白了,这就是为什么 Xcode 中的约束显示在 superViews 下而不是视图本身。仍然有语法问题。回到文档,也许它会在这个时候沉没。感谢您的洞察力。【参考方案2】:

该 |字符代表视觉格式语言中的超级视图,所以我想你想要:

@"|-0-[_contentView]-0-|"

然后您需要将约束添加到 self 而不是 contentView,因为您需要将其添加到可以看到所有参与者的视图中。

以下是视觉语言的参考: https://developer.apple.com/library/mac/#documentation/UserExperience/Conceptual/AutolayoutPG/Articles/formatLanguage.html#//apple_ref/doc/uid/TP40010853-CH3-SW1

您也可以完全避免使用视觉格式:

+(id)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c

【讨论】:

如果你将约束添加到self而不是contentView,那么管道(|)会引用self的superview吗?【参考方案3】:

尝试检查约束,它们是否正确添加到视图中

例如:

UIView *yellowView = [[UIView alloc] init];
yellowView.backgroundColor = [UIColor yellowColor];
yellowView.translatesAutoresizingMaskIntoConstraints = false;
[self.view addSubview:yellowView];

//ios 9 last
NSLayoutConstraint *heightAnchor = [yellowView.heightAnchor constraintEqualToAnchor:self.purView.heightAnchor];
// addConstraints
[self.view  addConstraints:@[heightAnchor]];
[self.view setNeedsLayout];

如果添加heightAnchor to yellowView 喜欢关注。它会显示错误

[yellowView addConstraints:@[heightAnchor]];

【讨论】:

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

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

UICollectionViewCell 以编程方式自动布局

iOS - 以编程方式使用自动布局将 UIView 定位在超级视图的中心

如何以编程方式使用自动布局以编程方式添加 UIview?

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

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