如何在 iOS 6 中使用具有多个子视图的现有自定义视图自动布局

Posted

技术标签:

【中文标题】如何在 iOS 6 中使用具有多个子视图的现有自定义视图自动布局【英文标题】:How to Auto Layout with existing Custom View with multiple subviews in iOS 6 【发布时间】:2013-03-26 11:46:02 【问题描述】:

我正在尝试使用约束来制作布局,但我有许多带有内部嵌套子视图的自定义控件。我正在将约束添加到顶视图(CustomView),但它没有正确布置子视图。

例如。我有 TextFieldWithLabel 类,它在 UITextField 的顶部和下方显示标签,我正在创建 TextFieldWithLabel 的实例并添加到带有约束的超级视图。

但它没有按预期显示结果。 虽然它可见但没有放在我想要的位置。为此,我不想更改整个 TextFieldWithLabel 类的敌人自动布局。

请帮忙!

usernameTextField = [[TextFieldWithLabel alloc] initWithFrame:CGRectMake(0, 0, 100, 50) name:@"UserName"];
    [usernameTextField setTranslatesAutoresizingMaskIntoConstraints:NO];
    [superview addSubview:usernameTextField];
    NSLayoutConstraint* myConstraint = [NSLayoutConstraint constraintWithItem:usernameTextField
                                                                    attribute:NSLayoutAttributeCenterY
                                                                    relatedBy:NSLayoutRelationEqual
                                                                       toItem:superview
                                                                    attribute:NSLayoutAttributeCenterY
                                                                   multiplier:1
                                                                     constant:0];

    [superview addConstraint:myConstraint];

    myConstraint = [NSLayoutConstraint constraintWithItem:usernameTextField
                                                attribute:NSLayoutAttributeCenterX
                                                relatedBy:NSLayoutRelationEqual
                                                   toItem:superview
                                                attribute:NSLayoutAttributeCenterX
                                               multiplier:1
                                                 constant:0];
    [superview addConstraint:myConstraint];

屏幕截图: 这里它没有居中,而且文本字段 (RedColor) 也不能点击。标签和文本字段放置在 TextFieldWithLabel 内。 请注意:TextFieldWithLabel 是 ComponentView 的子类,而 ComponentView 是 UIView 的子类。所以我怀疑这可能是问题所在?我是否也需要自动布局 ComponentsView。

【问题讨论】:

请展示您是如何创建自定义控件的 - 它们是在代码中、在 xib 中、使用自动布局、弹簧和支柱制作的吗?还请附上屏幕截图,指出错误的布局在哪里。目前很难回答这个问题。 感谢回复,我正在代码中创建CustomView。 那么,您可以编辑问题以包含代码吗? 添加的代码请看一下 因此,您尝试将 textFieldWithLabel 置于超级视图的中心。它是什么样子的?是不是在正确的地方,但尺寸不对? 【参考方案1】:

在自动布局下,您的帧大小将被忽略(您在initWithFrame: 期间使用的那个)。您已指定定位约束,但与大小无关,因此您的 TextFieldWithLabel 位于屏幕中心,大小为零。

文本字段和标签仍然可见,因为您说您没有在此控件内部使用自动布局 - 大概您确实在那里设置了一些框架和自动调整大小的蒙版。因此,文本字段和标签超出​​了TextFieldWithLabel 的范围,因此它们是可见的,但可能不会响应触摸。

要解决这个问题,你有两个选择:

在内部使用自动布局 - 例如,如果您有此约束(在 VFL 中),那么它将自动为您的控件提供高度:"V:|-[label]-[textField]-|"

在上面的代码中添加尺寸限制 - 使用与 initWithFrame 中相同的尺寸。这是一个设置高度的方法:

[NSLayoutConstraint constraintWithItem:usernameTextField 
                             attribute:NSLayoutAttributeHeight 
                             relatedBy:NSLayoutRelationEqual 
                                toItem:nil 
                             attribute:NSLayoutAttributeNotAnAttribute 
                            multiplier:0.0 
                              constant:50.0];

我在 UIView 上有一个类别来简化常见约束 here 的创建。使用类别代码 centerInView:constrainToSize:

【讨论】:

感谢您的帮助!!会试试这个,让你知道,还有什么方法可以在设置约束后立即获取 UIVIew 的大小? 您需要等到布局发生 - 视图控制器中的viewDidLayoutSubviews 是一个好地方。 感谢现在工作!!问题在于尺寸设置,我们需要使用约束来设置尺寸。【参考方案2】:

如果您不希望您的标签(或其他子视图)具有调整大小的约束,那么...

    self.YourLabel.translatesAutoresizingMaskIntoConstraints = NO;

【讨论】:

【参考方案3】:

不确定您如何处理 TextFieldWithLabel,我可能不清楚它实际上是 UIView 子类(我总是将 UIView 子类命名为以 View 结尾)

在这种情况下,您最终会在构建应用程序时得到一个偷偷摸摸的 View。在 InterfaceBuilder 中,您拖入了一个视图,并且可能将类设置为“TextFieldWithLabel_View_”。您执行了通常的“自定义约束”,但是如果“TextFieldWithLabel_View_”类是 UIView 的子类,则您引入了一个中间层。

在您布局标签和文本字段的 XIB 或代码中,您可能已经相对于您自己的子类的 UIView 设置了正确的约束。

问题是,子类 UIView 的约束没有链接到已使用 StoryBoard 拖入的 View。

这就是我所做的:

@interface TextFieldWithLabel__View__ ()
@property (strong, nonatomic) IBOutlet UIView *backgroundView;
@property (weak, nonatomic) IBOutlet UILabel *labelText;
....
....
@end



-(id)initWithCoder:(NSCoder *)decoder
    if ((self = [super initWithCoder:decoder]))
        [self addSubview:[[[NSBundle mainBundle] loadNibNamed:@"TextFieldWithLabel__View__" owner:self options:nil] objectAtIndex:0]];
    

    // Set the backgroundView (the one needed for the IB to create a UIView for XIB)
    // Left, Right, Top and Bottom to 0

    _backgroundView.translatesAutoresizingMaskIntoConstraints = NO;
    [self addConstraint:[NSLayoutConstraint constraintWithItem:_backgroundView
                                                     attribute:NSLayoutAttributeLeft
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:self
                                                     attribute:NSLayoutAttributeLeft
                                                    multiplier:0
                                                      constant:0
                         ]
     ];
    [self addConstraint:[NSLayoutConstraint constraintWithItem:_backgroundView
                                                     attribute:NSLayoutAttributeRight
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:self
                                                     attribute:NSLayoutAttributeRight
                                                    multiplier:1
                                                      constant:0
                         ]
     ];
    [self addConstraint:[NSLayoutConstraint constraintWithItem:_backgroundView
                                                     attribute:NSLayoutAttributeTop
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:self
                                                     attribute:NSLayoutAttributeTop
                                                    multiplier:0
                                                      constant:0
                         ]
     ];
    [self addConstraint:[NSLayoutConstraint constraintWithItem:_backgroundView
                                                     attribute:NSLayoutAttributeBottom
                                                     relatedBy:NSLayoutRelationEqual
                                                        toItem:self
                                                     attribute:NSLayoutAttributeBottom
                                                    multiplier:1
                                                      constant:0
                         ]
     ];
    return self;

现在,当您想要重新定义 CustomView、拖动项目、调整分配区域的大小或其他任何事情时,它会很好地通过 CustomView 的约束表单到您的 TextFieldWithLabel_View_

并在情节提要中勾选“AutoResize Subviews”

希望对您有所帮助。

附:不要放弃 AutoLayout...掌握它!

【讨论】:

以上是关于如何在 iOS 6 中使用具有多个子视图的现有自定义视图自动布局的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS SDK 中禁用 UIView/UIViewController 的“突出显示子视图”消息?

将具有多个子视图的视图截图为 wkwebview

如何在键盘视图和顶视图中添加自定义子视图? (iOS8 及以下无法在 iOS9 中使用)

调用具有多个子视图层次结构的协议方法

以编程方式添加具有约束的多个子视图会引发异常

如何将 UIView 插座连接到自定义子视图