Anmol Mago
Anmol Mago

Reputation: 23

Generate buttons programmatically without overlap in Objective-C xcode

I have spent a few hours trying to accomplish what I thought would be a simple task. I am trying to generate 10 non-rotated square buttons on my iphone screen programmatically without them overlapping. Whenever I get what I think is the correct code, the app just hangs. Heres what I am trying to do so far:

First I have a while loop that keeps attempting to generate buttons until there are 10 (hence the hang). This loop calculates a random width and height to generate the button on.

I then attempt to check if the button would cause overlap with any button currently placed on screen (note: this is in intervals for efficiency, but has been tested without). If the button may overlap, I "continue;", but if not then I generate the button.

After generate the button I put the coordinates where other buttons should not be placed into their specific, axis based arrays to check in the loops ahead.

This is my code:

- (void)addNumbers{
    int width = [[UIScreen mainScreen] bounds].size.width - 70;
    int height = [[UIScreen mainScreen] bounds].size.height - 110;
    NSMutableArray* xarray = [[NSMutableArray alloc] init];
    NSMutableArray* yarray = [[NSMutableArray alloc] init];
    int buttons = 0;
    while(buttons < 10) {
        int x = 10*floor(10+arc4random_uniform(width)/10);
        int y = 10*floor(50+arc4random_uniform(height)/10);
        NSLog(@"The coords are: %i, %i",x,y);
        if([xarray containsObject:[NSNumber numberWithInt:x]] && [yarray containsObject:[NSNumber numberWithInt:y]]){
            NSLog(@"Triggered");
            continue;
        }
        [self generateButton:x :y :buttons];
        buttons++;
        for(int i = 0; i < 6; i++){
            [xarray addObject:[NSNumber numberWithInt:(x+i*10)]];
            [yarray addObject:[NSNumber numberWithInt:(y+i*10)]];
            [xarray addObject:[NSNumber numberWithInt:(x-i*10)]];
            [yarray addObject:[NSNumber numberWithInt:(y-i*10)]];
        }
    }
}

- (void)generateButton:(int)x :(int)y :(int)num{
    UIButton * btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    btn.frame = CGRectMake(x, y, 60, 60);
    [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [btn setBackgroundColor:[UIColor whiteColor]];
    btn.titleLabel.font = [UIFont fontWithName:@"Avenir" size:40.0f];
    [btn setTitle:[NSString stringWithFormat:@"%d",num] forState:UIControlStateNormal];
    [self.view addSubview:btn];
    [self.squareArray addObject:btn];
}

Please help me :'(

Also I am new to Objective-C (probably obvious) so feel free to comment on any way I can improve my code or efficiency.

Upvotes: 2

Views: 1046

Answers (1)

Arbitur
Arbitur

Reputation: 39091

I'll give you what I would've done.

-(BOOL)isButtonOverlapping:(NSArray *)array button:(UIButton *)btn {
    for (UIButton *btn_ in [array copy]) {
        if (CGRectIntersectsRect(btn_, btn)) return YES;
    }
    return NO;
}

-(void)addNumbers {
    int width = [[UIScreen mainScreen] bounds].size.width - 70;
    int height = [[UIScreen mainScreen] bounds].size.height - 110;

    NSMutableArray *buttonsArray = [NSMutableArray new];

    for (short button = 0; button < 10; button++) {
        UIButton *btn = [self generateButton:x :y :button];

        do {
            btn.center = CGPointMake(rand() % width, rand() % height);
        } while ([self isButtonOverlapping:buttonsArray button:btn]);

        [buttonsArray addObject:btn];
    }
}

-(UIButton *)generateButton:(int)x :(int)y :(int)num {
    UIButton * btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    btn.frame = CGRectMake(x, y, 60, 60);
    [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
    [btn setBackgroundColor:[UIColor whiteColor]];
    btn.titleLabel.font = [UIFont fontWithName:@"Avenir" size:40.0f];
    [btn setTitle:[NSString stringWithFormat:@"%d",num] forState:UIControlStateNormal];
    [self.view addSubview:btn];
    [self.squareArray addObject:btn];

    return btn;
}

Upvotes: 2

Related Questions