0

Question: How do I target one of many dynamically created UIButtons so I can change its properties?

Background: I have a storyboard with a UIViewConroller. When this UIVC loads a UIScrollView is added, to which a UIImageView is placed that has an exhibition floor plan. Each exhibitor has an entry in a database that contains its location on the floor plan. When the UIVC is loaded a loop is run for all exhibitors and each one has a UIButton drawn on the UIIV. When a UIB is clicked the button background colour is changed (to confirm which exhibitor has been selected) and a UIAlertView is shown with information about that exhibitor. When the UIAV's 'cancel' (ok) button is pressed the UIAV closes and the background highlight colour that was applied previously should be removed but here is where I am having the problem. I am unable to target the UIButton so I can change its background colour.

What I have tried so far: As each button is created I am giving it a tag and a title and recording both in an array. When the 'cancel' button is pressed on the UIAlertView I have tried checking the tag in the array but I still cannot actually target the UIButton.

I was thinking something like this:

// obviously not correct syntax but the kind of thing I want
[exhibitorBtn(tag) setBackgroundColor:[UIColor greenColor]];

So, say I have 12 UIButtons all called exhibitorBtn but with different titles and tags:

  • Object ----- Name ---------- Title -------- Tag

  • UIButton -- exhibitorBtn -- Glaxo ------ 1

  • UIButton -- exhibitorBtn -- Porsche --- 2

  • UIButton -- exhibitorBtn -- Rolex ------- 3 < How would I target that button's properties?

Edit - added the code that creates the buttons just to clarify:

 for (NSDictionary *dict in exhibitorStandArray) {

    NSInteger currentPosition = [exhibitorStandArray indexOfObject:dict];
    NSLog(@"Position in array = %li", (long)currentPosition);
    if (![dict[@"locCoords"] isEqual: @""]) {

        NSInteger buttonTag = [exhibitorStandArray indexOfObject:dict];
        NSString *standNo = dict[@"locStandNo"];
        NSMutableDictionary *buttonDictionary = [[NSMutableDictionary alloc] init];
        [buttonDictionary setObject:[NSNumber numberWithInteger:buttonTag] forKey:@"buttonTag"];
        [buttonDictionary setObject:standNo forKey:@"buttonStandNo"];

        [_masterButtonList addObject:buttonDictionary];

        NSString *locCoords = dict[@"locCoords"];
        NSArray *tempArray =[locCoords componentsSeparatedByString:@","];
        tlcTop = [[tempArray objectAtIndex:0] integerValue];
        tlcLeft = [[tempArray objectAtIndex:1] integerValue];
        brcTop = [[tempArray objectAtIndex:2] integerValue];
        brcRight = [[tempArray objectAtIndex:3] integerValue];
        buttonWidth = brcRight - tlcLeft;
        buttonHeight = brcTop - tlcTop;

        testBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        testBtn.frame = CGRectMake(tlcTop, tlcLeft, buttonHeight, buttonWidth);
        testBtn.titleLabel.text = standNo;
        testBtn.tag = buttonTag;
        NSLog(@"UIButton Title = %@", testBtn.titleLabel.text);
        NSLog(@"UIButton Tag = %li", (long)testBtn.tag);

        testBtn.titleLabel.hidden = YES;

        [testBtn addTarget:self action:@selector(displayInfo:) forControlEvents:UIControlEventTouchUpInside];

        [_buttonArray addObject:testBtn];
        [_imageView addSubview:testBtn];
     }   
}
GingerHead
  • 8,130
  • 15
  • 59
  • 93
Agamemnon
  • 587
  • 2
  • 15
  • 44

4 Answers4

1

Why can't you just use viewWithTag:

    UIButton * button = (UIButton *)[self.scrollView viewWithTag:tag];
Flexicoder
  • 8,251
  • 4
  • 42
  • 56
0

Your code probably looks something like this:

for (int i = 0; i < 5; i++)
{
    UIButton *exhibitorBtn = [[UIButton alloc] initWithFrame:etc..];
    exhibitorButton.tag = i;
    [scrollView addSubview:exhibitorBtn];
}

Just change the loop so every button will be added to an array, too. Declare a NSMutableArray as a property: @property (strong, nonatomic) NSMutableArray *buttonsArray;

And @synthesize and initialise it in your init method. buttonsArray = [[NSMutableArray alloc] init]

Then, change the loop like I said above:

for (int i = 0; i < 5; i++)
{
    UIButton *exhibitorBtn = [[UIButton alloc] initWithFrame:etc..];
    exhibitorButton.tag = i;
    [buttonsArray addObject:exhibitorBtn];
    [scrollView addSubview:exhibitorBtn];
}

Finally, when you want to access the buttons:

for (int i = 0; i < [buttonsArray count]; i++)
{
    UIButton *button = [buttonsArray objectAtIndex:i];

    if (button.tag == 3) { // This is the button you wanted to target!
        [button setHidden:YES];
    }
}
Ramon
  • 1,415
  • 9
  • 18
  • Why use increasing `tag`, if buttons are already in an array sequence? – user3125367 Feb 13 '14 at 10:21
  • I was just giving an example of his code. I assume the owner set the tags in Interface Builder anyway. :] – Ramon Feb 13 '14 at 10:23
  • No the tags were set when I looped through the exhibitors in the database and created the buttons and assigned their tags there. The tags weren't just 1,2,3 per se, as they matched the stand numbers of the exhibitors so an array as shown would not have worked perfectly. A dictionary, on the other hand, would probably have worked fine. – Agamemnon Feb 13 '14 at 10:35
0

Let's make it clear: you did set target and action of UIButton to controller's IBAction method and get the button as sender argument. Now you show UIAlertView and after it is dismissed, you want to send some message to that button, right?

Another method is to set delegate property for UIAlertView and respond to – alertView:clickedButtonAtIndex: delegate method. Trouble is that sender is lost at that point. You may use objc_setAssociatedObject to associate UIButton with UIAlertView and the retrieve it back when delegate method fires:

#import <objc/runtime.h>
static char myButtonKey = 0; // to use address as a key (value is irrelevant)

- (IBAction)buttonDidClick:(id)button
{
    UIAlertView *alertView = <setup alert>;
    [alertView setDelegate:self];
    objc_setAssociatedObject(alertView, &myButtonKey, button, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    <show alert>;
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    UIButton *thatButton = objc_getAssociatedObject(alertView, &myButtonKey);
    <use thatButton>;
}
user3125367
  • 2,920
  • 1
  • 17
  • 17
  • I have read that as a potential method for resolving this kind of issue. I will try the array method first and then this. – Agamemnon Feb 13 '14 at 10:24
  • @Ryan Just curious, how do you know `tag` after UIAlertView is dismissed? If you remember it in temporary controller field when the button is pressed, then you can remember an actual index in button array and not deal with tag searching at all. – user3125367 Feb 13 '14 at 10:28
  • I kind of cheated by creating a property to hold the 'currentTag'. When the button is pressed, this property is updated with the current button's tag. – Agamemnon Feb 13 '14 at 10:30
  • @Ryan :) Why not cheat with holding `currentButton` then? – user3125367 Feb 13 '14 at 10:30
  • I didn't think of that, seems I was perhaps over-thinking things :S – Agamemnon Feb 13 '14 at 10:32
0

Try to create button in this way and add selector to them :

for (int i = 0; i < 5; i++)
{
    UIButton *button = [[UIButton alloc] initWithFrame:CGRectZero];

    button.tag = i;
    [button addTarget:self
               action:@selector(buttonPressedMethod:)
     forControlEvents:UIControlEventTouchDown];
    [button setTitle:@"Show View" forState:UIControlStateNormal];

    // add button to subview here
}

In method, just do whatever, you want to do :

- (void) buttonPressedMethod : (id) sender {
UIButton *selectedButton = (UIButton *)sender;

  if (selectedButton.tag == 0) {

  }

  else if (selectedButton.tag == 1) {

  }


  else {

  }

}
Samkit Jain
  • 2,523
  • 16
  • 33
  • This answer would probably have worked but I chose Flexicoder's as it is simpler and needed less modification to mine. Also the tags are set based on their position in the database (makes things much simpler later on) and so the array index would not have matched up, therefor I would probably have needed a dictionary instead. – Agamemnon Feb 13 '14 at 10:31