如何为具有随机位置的项添加约束

时间:2014-04-28 01:50:04

标签: ios objective-c

我有一个ios应用程序,我在随机生成的位置添加一个可变数字(2到10个)标签。这一切都是以编程方式完成的。这就是确定标签位置的方式。

int width = self.view.frame.size.width - 200;
int height = self.view.frame.size.height - 200;
newFrame.origin.x = arc4random() % width;
newFrame.origin.y = 80 + arc4random() % (height-80);

所有标签在创建并添加到视图后添加到数组self.viewLabels中,否则没有永久引用它们,因为它们是在循环中创建的

while (numViews < (numLabels)){

        CustomLabel *timer = [[CustomLabel alloc] init];;
        ....

除非我将应用程序转换为横向视图,否则它可以正常工作。一些标签消失在纵向视图的底部。我正在考虑以编程方式添加约束,我理解第一步是添加需要约束到此字典的元素

     NSDictionary *views = NSDictionaryOfVariableBindings(button, button2);

由于我只在数组self.viewLabels中引用了这些标签,因此我试图找出是否可以获取该字典中的标签。我尝试使用迭代器为标签

创建唯一的名称
 for (int i = 0; i < [self.viewLabels count]; i++){
        CustomLabel * label[i] = self.viewLabels[i];

    }

这不起作用,即使它确实如此,我也无法弄清楚如何将它们添加到词典中。即使我在字典中获取它们,如何在视图中为具有随机位置的项添加约束?

你能否提出我可以在这种情况下使用的策略?

更新

如果在我随机生成的位置后无法添加约束,在创建位置时是否可以执行某些操作以确保它们在横向和纵向都可见?

根据@rdelmar的第一个答案更新2-,我尝试了下面的代码(即添加没有框架的标签,然后在添加到视图后添加约束)。但是没有标签出现在屏幕上。您可以通过我已评论过的行看到我的代码之前是如何形成的。我之前在随机位置添加了标签......

    while (numViews < (numLabels)){

        CustomLabel *label = [[CustomLabel alloc] init];;

//        
//        label.frame = CGRectMake(0, 0, 150, 50);   //removed the frame
        label.text =  @"blah";


//        newFrame = label.frame;
//        int width = self.view.frame.size.width - 200;
//        int height = self.view.frame.size.height - 200;
//        newFrame.origin.x = arc4random() % width;
//        newFrame.origin.y = 80 + arc4random() % (height-80);
//        label.frame = newFrame;
        [label setFont:[UIFont systemFontOfSize:50]];

        UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc]
                                       initWithTarget:self action:@selector(handleGesture:)];
        tgr.numberOfTapsRequired = 1;
        tgr.numberOfTouchesRequired = 1;
        [label addGestureRecognizer:tgr];

        label.userInteractionEnabled = YES;
        [label setTranslatesAutoresizingMaskIntoConstraints:NO];
        [self.view addSubview:label];
        [self.gameClocks addObject: label];
        numViews += 1;

        [self.view addConstraint:
         [NSLayoutConstraint constraintWithItem:label
                                      attribute:NSLayoutAttributeWidth
                                      relatedBy:NSLayoutRelationEqual
                                         toItem:self.view
                                      attribute:NSLayoutAttributeWidth
                                     multiplier:1
                                       constant:0]];
        [self.view addConstraint:
         [NSLayoutConstraint constraintWithItem:label
                                      attribute:NSLayoutAttributeHeight
                                      relatedBy:NSLayoutRelationEqual
                                         toItem:self.view
                                      attribute:NSLayoutAttributeHeight
                                     multiplier:1
                                       constant:0]];

1 个答案:

答案 0 :(得分:1)

尝试以不同的方式考虑这一点 - 您不会为具有随机生成位置的视图添加约束,您可以创建随机约束,从而导致视图具有随机位置。因此,当您创建视图时,您不会给它们任何框架。您创建标签,将其添加到子视图,然后添加约束。如果您希望标签在纵向和横向都可见,最好使用乘数而不是约束的常量值,因此位置相对于视图的大小(与某些边缘不是恒定距离) 。为此,您将使用constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:,而不是可视格式语言,因此您不必担心视图字典。使用乘数时,必须使用超视图的右边缘或下边缘,因为它们具有非零值(而顶部和左侧不具有)。

编辑后:

这是一种方法。我通过将0到1之间的随机数传递给乘数系数来创建随机位置。为了将标签保持在视图内,我将标签的左侧或右侧固定,这取决于乘数值是否会导致标签靠近超视图的左侧或右侧(与顶部或顶部相同)底部)。我还使标签的高度和宽度相对于视图的大小,因此标签更短但横向更宽。

@interface ViewController ()
@property (strong,nonatomic) NSMutableArray *labelArray;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.labelArray = [NSMutableArray new];
    while (self.labelArray.count <10) {
        UILabel *label = [UILabel new];
        label.backgroundColor = [UIColor orangeColor];
        [self.view addSubview:label];
        [self.labelArray addObject:label];
        [self createConstraintsForRanomPositions:label];
    }

    for (int i = 0; i< self.labelArray.count; i++) {
        [self.labelArray[i] setText:[NSString stringWithFormat:@"Label %d", i]];
    }
}


-(void)createConstraintsForRanomPositions:(UIView *) view {
    [view setTranslatesAutoresizingMaskIntoConstraints:NO];
    CGFloat rightMultiplier = arc4random_uniform(100)/ 100.0;
    CGFloat bottomMultiplier = arc4random_uniform(100)/ 100.0;

    NSLayoutConstraint *con1;
    if (bottomMultiplier <= .2) {
        con1 = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:0 toItem:self.view attribute:NSLayoutAttributeBottom multiplier:bottomMultiplier constant:0];
    }else{
        con1 = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:0 toItem:self.view attribute:NSLayoutAttributeBottom multiplier:bottomMultiplier constant:0];
    }

     NSLayoutConstraint *con2;
    if (rightMultiplier <= .2) {
        con2 = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeft relatedBy:0 toItem:self.view attribute:NSLayoutAttributeRight multiplier:rightMultiplier constant:0];
    }else{
        con2 = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeRight relatedBy:0 toItem:self.view attribute:NSLayoutAttributeRight multiplier:rightMultiplier constant:0];
    }

    NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:0 toItem:self.view attribute:NSLayoutAttributeWidth multiplier:.2 constant:0];
    NSLayoutConstraint *con4 = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:0 toItem:self.view attribute:NSLayoutAttributeHeight multiplier:.1 constant:0];
    [self.view addConstraints:@[con1, con2, con3, con4]];
    [self.view layoutIfNeeded]; // this is needed, otherwise the frames are all {{0,0}, {0,0}} in the following forloop

    for (UIView *placedView in self.labelArray) { // rejects any label that overlaps with any other
        if (![placedView isEqual:view] && CGRectIntersectsRect(CGRectInset(view.frame, -2, -2), placedView.frame)) {
            [view removeFromSuperview];
            [self.labelArray removeObject:view];
            break;
        }
    }
}