以编程方式创建具有多个标签的 UIView

Posted

技术标签:

【中文标题】以编程方式创建具有多个标签的 UIView【英文标题】:Programatically creating a UIView with multiple Labels 【发布时间】:2014-01-08 15:53:27 【问题描述】:

Xcode Interface Builder 问题 我个人不喜欢界面生成器在 Xcode 中的工作方式。在这个例子中,我试图创建一个相当复杂的视图控制器。在视图控制器的viewDidLoad 上,我显示了一个自定义警报视图(因此)。它实际上不是警报视图,而更多的是向用户显示一些信息的视图。我有一个暗淡的背景视图和一个在此之上的视图。如果我尝试在界面生成器中创建它,它会变得过于复杂,因为您无法在后台选择视图并移动它们等,而不会将子视图放入错误的视图等等......

场景 我想要做的是创建一个包含一些标签和一个按钮的视图。视图控制器具有基于此的难度属性,它将在标签/标签数量中具有不同的文本。 IE。简单 -- 3 个标签 硬——4个标签

我像这样创建 dimmedView 和 alert(styled)View:

// Setup the dimmedView
UIView *dimmedView = [[UIView alloc] initWithFrame:self.view.frame];
dimmedView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.6];

// Setup the startingAlertView
UIView *startingAlertView = [[UIView alloc] init];
startingAlertView.backgroundColor = [UIColor whiteColor];

然后我根据一些逻辑创建三/四个标签,并根据逻辑将必要的标签添加到startingAlertView

显而易见的问题是,在任何时候都没有设置视图框架。这意味着它返回 0,0,0,0。我想要发生的是根据添加的标签获取所需高度的视图。

我正在为 ios7 构建并使用自动布局。我是否应该设置约束,然后可能会调整视图中的相关高度和位置?

【问题讨论】:

@MarcoPace 或者,使用自动布局,旨在解决这个问题。 @jrturton 好,我没有读最后一句话。由于它没有使用 IB,我错误地认为他不想使用它们。感谢您的回复。 谢谢,在这个例子中 IB 没有用……主要是因为这是一个顶层视图,下面有一个复杂的视图。如果您可以在为其他人工作时切换视图以在 IB 中显示/隐藏...现在这将很有用 【参考方案1】:

我正在为 IOS7 构建并使用自动布局。我是否应该设置约束,然后可能会调整视图中的相关高度和位置?

是的。您不要在自动布局下使用initWithFrame:,或者更确切地说,您可以使用,但框架会被忽略。使用CGRectZero 的框架创建调光视图,将translatesAutoresizingMasksToConstraints 设置为NO,将其添加到主视图并创建约束,将其固定到超级视图的所有边缘。

然后,添加警报视图,再次使用零框架并将translates... 属性设置为 NO。创建约束以使该视图在您的调光视图中居中。该视图将从其子视图中获取其大小,因为标签具有固有大小。

将您的标签添加为此视图的子视图,框架为零,translates... 设置为 NO。根据它们的内容,您可能希望设置首选的最大布局宽度或宽度约束。

创建约束,将标签固定到超级视图的左右边缘,并将标签排列在垂直“堆栈”中。在每种情况下,您都可以添加填充以使您的警报有点边框。

这可能看起来像大量代码,因此您可能想阅读我在visual format for auto layout 和creating constraints in code 上写的文章,以及相关的autolayout convenience category,以使您的生活更轻松。

【讨论】:

首先感谢您的回答。其次,博客文章很棒,它真的帮助我自己找到了答案。你是对的,它需要一些代码和玩耍,但这极大地帮助了我对约束编码的理解,所以谢谢!!! 你好,其实我一直用CGRectZero,直到我使用这个开源项目github.com/BaiduLBS/BaiduMapKit,中国最流行的地图工具包。当在代码中实例化其地图视图(UIView 的子类)并将 CGRectZero 传递给 init(frame:) 时,它总是第一次显示不正确!在第一次可以正确显示后,任何大于零的尺寸都不会出现这个问题。我一直不明白为什么。你有什么想法吗? @Qiulang 可能它正在对 initWithFrame 上的帧值做一些事情,但该项目没有任何源代码,所以我无法判断。向他们提出问题? 谢谢。是的,我向他们提出了问题,他们还没有回复。我也向苹果提出了这个问题,苹果正在与我讨论。我问苹果是否使用 CGRectZero 是最好的方法,因为我没有看到任何“官方”文件提到这一点。【参考方案2】:

如果您要使用自动布局路线,那么您可以添加约束,以保持每个标签之间的适当间距,以及视图顶部和底部与第一个和最后一个标签之间的适当间距。但是,如果您不在 Interface Builder 中执行此操作,您也可以跳过使用自动布局,因为在添加标签时调整视图的高度相当简单。

您可以首先将视图的高度设置为您希望标签周围的顶部和底部空间的大小。然后每次添加标签时,将标签的高度加上标签之间的空间高度添加到其中。

你也可以等到你添加了所有你想要的标签,然后将高度设置为底部标签的 y 位置加上它的高度加上你希望标签周围的底部空间。

【讨论】:

【参考方案3】:

是的,使用自动布局可以从父视图中获取边界。

这是一个简单的例子,注意我们没有使用框架,而是使用 CGRectZero 作为我们的 UILabel,定位来自updateConstraints。我正在使用Visual Format Language 来布局我推荐的标签,如果您以编程方式进行的话。

在这里,我们将标签设置为父视图的宽度,然后彼此堆叠。

#import "View.h"

@implementation View
    UILabel *_label1;
    UILabel *_label2;
    UILabel *_label3;


- (id)initWithFrame:(CGRect)frame

    self = [super initWithFrame:frame];
    if (self) 
        _label1 = [[UILabel alloc] initWithFrame:CGRectZero];
        _label1.translatesAutoresizingMaskIntoConstraints = NO;
        _label1.text = @"LABEL 1";

        _label2 = [[UILabel alloc] initWithFrame:CGRectZero];
        _label2.translatesAutoresizingMaskIntoConstraints = NO;
        _label2.text = @"LABEL 2";

        _label3 = [[UILabel alloc] initWithFrame:CGRectZero];
        _label3.translatesAutoresizingMaskIntoConstraints = NO;
        _label3.text = @"LABEL 3";

        [self addSubview:_label1];
        [self addSubview:_label2];
        [self addSubview:_label3];
    


    [self updateConstraintsIfNeeded];

    return self;


-(void)updateConstraints

    [super updateConstraints];

    NSDictionary *_viewsDictionary = NSDictionaryOfVariableBindings(_label1,_label2,_label3);


    // Set the contraintsto span the entire width of the super view
    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_label1]-|"
                                                                   options:0
                                                                   metrics:nil
                                                                     views:_viewsDictionary];

    [self addConstraints:constraints];

    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_label2]-|"
                                                                   options:0
                                                                   metrics:nil
                                                                     views:_viewsDictionary];
    [self addConstraints:constraints];

    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_label3]-|"
                                                                   options:0
                                                                   metrics:nil
                                                                     views:_viewsDictionary];

    [self addConstraints:constraints];


    // Last setup the vertical contraints other wise they will end up in a random place
    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[_label1]-[_label2]-[_label3]"
                                                                   options:0
                                                                   metrics:nil
                                                                     views:_viewsDictionary];
    [self addConstraints:constraints];


/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect

    // Drawing code

*/

@end

【讨论】:

以上是关于以编程方式创建具有多个标签的 UIView的主要内容,如果未能解决你的问题,请参考以下文章

无法更改以编程方式生成的 UIView 中的标签

具有 UIView 继承类的 UIViewController,以编程方式

使用自动布局约束以编程方式创建四个具有相同高度和宽度的 UIView

在 UIView 中以编程方式创建的 UILabel 未更新

对子类 UIView 的约束会抛出以编程方式创建的 UILabel 位置

从 UIView 以编程方式创建 UIImage