2

I am developing an iOS application. I have 35 buttons on the storyboard. Is there anyway I can use a random generator to randomly rearrange or shuffle the buttons and still maintain the button's functionality?

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Param
  • 39
  • 5

5 Answers5

0

That is possible, it will require some coding:

  • Create NSMutableArray with all buttons of the view in it.
  • Randomize its order.
  • Run over the buttons array and on each iteration keep last button view and switch its rect with current button and vice versa.

For better understanding, here is the code (ready for use, just copy paste):

- (void)viewDidLoad {
    [super viewDidLoad];

    // Getting buttons into array
    NSMutableArray * buttonsArr = [self getButtonsArray];

    // Shuffling buttons location
    if(buttonsArr && [buttonsArr count]) {
        [self randomizeButtonsLocation:buttonsArr];
    } else {
        NSLog(@"No buttons found");
    }
}

- (void)randomizeButtonsLocation:(NSMutableArray *)buttonsArr {

    // Randomizing order in button array
    buttonsArr = [self randomizeArr:buttonsArr];
    UIButton * lastBtn = nil;

    for (UIButton * btn in buttonsArr) {
        if(!lastBtn) {
            lastBtn = btn;
        } else {

            // Put a side frames of last and current buttons
            CGRect lastBtnRect = [lastBtn frame];
            CGRect currentBtnRect = [btn frame];

            // Switch frames
            [btn setFrame:lastBtnRect];
            [lastBtn setFrame:currentBtnRect];

            // Keeping last btn for next iteration
            lastBtn = btn;
        }
    }
}

- (NSMutableArray *)getButtonsArray {

    // Getting all buttons in self.view and inserting them into a mutable array
    NSMutableArray * resultArr  = [[NSMutableArray alloc] init];
    for (UIButton * btn in [self.view subviews]) {
        if([btn isKindOfClass:[UIButton class]]) {
            [resultArr addObject:btn];
        }
    }

    return resultArr;
}

- (NSMutableArray *)randomizeArr:(NSMutableArray *)arr {
    NSUInteger count = [arr count];
    for (NSUInteger i = 0; i < count; ++i) {
        unsigned long nElements = count - i;
        unsigned long n = (arc4random() % nElements) + i;
        [arr exchangeObjectAtIndex:i withObjectAtIndex:n];
    }
    return arr;
}
Roy K
  • 3,319
  • 2
  • 27
  • 43
0

You can add all the button objects to an NSMutableArray called buttonsArray and then use the following loop to exchange the buttons:

for (int i = 0; i < buttonsArray.count; i++) {
   int random1 = arc4random() % [buttonsArray count];
   int random2 = arc4random() % [buttonsArray count];
   [buttonsArray exchangeObjectAtIndex:random1 withObjectAtIndex:random2];
}
Dawan
  • 156
  • 4
0

If each of the button is belongs to a class like below then its really easy to shuffle them,

MyRandomButton {
    NSInteger uniqueId;
    NSString *title;
    ....
    ....
}

Now, what you can do is, at initial, prepare number of objets of MyRandomButton (equals to count of buttons on your StoryBoard). And add it into a mutable array (NSMutableArray).

Like this,

for(NSInteger index  = 1; index <= 35; index++) {
    MyRandomButton *btnInfo = ...;
    btnInfo.uniqueId = index;
    btnInfo.title = @sometitle;
    [myButtonsArray addObject:btnInfo];
}

In next step, if you're done with something (and you want to shuffle all buttons) then get help from this question, What's the Best Way to Shuffle an NSMutableArray? to shuffle your array.

Loop through all buttons on your StoryBoard (in your case: 1 to 35).

for(NSInteger index  = 1; index <= 35; index++) {
    UIButton *button = (UIButton *)[yourView viewWithTag:index];
    MyRandomButton *btnInfo = [myButtonsArray objectAtIndex:(index-1)];         
    button.tag = btnInfo.uniqueId;
    [button setTitle:btnInfo.title forState:UIControlStateNormal];
}

Inside above loop, we've updated buttons title and tag.

Done!

Community
  • 1
  • 1
Hemang
  • 26,840
  • 19
  • 119
  • 186
0

For anyone who needs to do this in SWIFT, here's how:

func randomlyPositionAnswerButtons() {
    
    var posX = CGFloat()
    var posY_button1 = CGFloat()
    var posY_button2 = CGFloat()
    var posY_button3 = CGFloat()
    
   // if self.view.frame.size.height == 667 { /* ======== IPHONE 7, 7S, 8 ======== */
        
        posX = 24 // Set all buttons to start from 37
        
        posY_button1 = 310
        posY_button2 = 405
        posY_button3 = 500
        
  //  }
    
    let tab = [
        [1,2], [0,2], [0,1]
    ]
    
    let indexArray = [
        NSValue(cgRect:CGRect(x: posX, y: posY_button1, width: 350, height: 74)),
        NSValue(cgRect:CGRect(x: posX, y: posY_button2, width: 350, height: 74)),
        NSValue(cgRect:CGRect(x: posX, y: posY_button3, width: 350, height: 74))
        ] as NSMutableArray
    
    // Shuffle the array
    var p = UInt32()
    p = arc4random() % 3
    indexArray.exchangeObject(at: 0, withObjectAt: Int(p))
    indexArray.exchangeObject(at: tab[Int(p)][0], withObjectAt: tab[Int(p)][1])
    
    // Assign the buttons their new position
    optionButtonA.frame = (indexArray[0] as AnyObject).cgRectValue
    optionButtonB.frame = (indexArray[1] as AnyObject).cgRectValue
    optionButtonC.frame = (indexArray[2] as AnyObject).cgRectValue
    
}
-1

Rearranging the fixed buttons sounds like a headache, if only in terms of autolayout constraints.

Why don't you:

  1. Create and position 35 "generic" buttons on the storyboard, each with their own outlet (properties named button01, button02, etc.), or better: use an outlet collection?

  2. Assign a unique tag to each button (0, 1, 2, 3...) on the storyboard.

  3. Assign the same @IBAction method to all your buttons on the storyboard.

  4. At runtime, determine and assign a specific "role" to each button at random (and set each button's label accordingly). But keep track of which button is which, using -for example- a dictionary.

  5. The action linked to all buttons will use the tag of the sender and the information contained in the dictionary mentioned above to determine which "role" button was tapped, and act accordingly.

Does it make sense?

Nicolas Miari
  • 16,006
  • 8
  • 81
  • 189
  • So I currently have 35 buttons already named button 01 - 35 (each doing a different action). So what is the next step? I am slightly lost. – Param Dec 24 '15 at 07:41
  • You have 35 different "meanings" (= roles) that you want to assign to those buttons, right? Each one corresponds to a different button title. At runtime, shuffle those and assign them to the buttons, on to each. – Nicolas Miari Dec 24 '15 at 07:51