Make changes to a number of buttons programatically - ios

I have a view with 10 buttons and I want to use information from an array to set how many of the buttons are visible and what their title is.
The buttons are named option1BTN...option10BTN. The array has different data and size depending on what the user selects and I want to buttons to also reflect the changes.
The code below shows a for-do loop, that sets which button is visible and the button title
for (int i=0; i == [optionsArray count]; i++) {
self.option1BTN.hidden = NO;
[self.option1BTN setTitle:[optionsArray objectAtIndex:i] forState:UIControlStateNormal];
}
How can I change the button name (programatically) in the loop so that depending on the size of the array it changes to option1BTN then option2BTN...optionXBTN and so on?

NSArray *buttons = #[self.option1BTN, self.option2BTN]; // add all the buttons here
for (int i=0; i < buttons.count; i++) {
UIButton *button = buttons[i];
button.hidden = NO;
[button setTitle:[optionsArray objectAtIndex:i] forState:UIControlStateNormal];
// the previous line can be re-written as
//[button setTitle:optionsArray[i] forState:UIControlStateNormal];
}
The difference between this approach and using an IBOutletCollection (as Jeff suggests in his answer) is that the outlet collection does not guarantee the order of its items. If the order is important to you, you need to specify it yourself, like in my code snippet above.

You have two main options, one is to use an IBOutletCollection (if your buttons are created in Interface Builder). Each UIButton will be stored in the collection and you can retrieve the right button in the loop from the collection.
Example:
#property (nonatomic, strong) IBOutletCollection(UIButton) NSArray *buttons;
In IB, you will need to link each button to the IBOutletCollection. Then in your code you will be able to do:
for (int i = 0; i < optionsArray.count; i++) {
UIButton *tempButton = self.buttons[i];
tempButton.hidden = NO;
[tempButton setTitle:[optionsArray objectAtIndex:i] forState:UIControlStateNormal];
tempButton.hidden = NO;
}
The ordering of an IBOutletCollection is not always guaranteed so you may need to use a combination of IBOutletCollection and view tagging (see end of post). For more information on IBOutletCollection's see NSHipster's article
Second option is if your buttons are created programmatically, store each button in an NSMutableArray as you create it:
#property (nonatomic, strong) NSMutableArray *buttons;
UIButton *myButton;
// Do something...
[self.buttons addObject:option1BTN];
Then use the same loop as before.
A third (not recommended option), would be to tag each UIButton and then you can use the viewWithTag: method to retrieve the button. E.g. using the above code again but getting the button with:
UIButton *tempButton = [self.view viewWithTag:i];

Related

iOS: setting alphas of multiple buttons at once

Okay, so I don't really know if NSDictionary is the correct approach to this, but I am using a fade animation to take different groups of buttons on and off a screen. I want to "compartmentalize" them, so to speak, into different groups so I can do this in one or two lines without having to rewrite all the buttons names every time (there are a good amount). Any ideas on how to do this?
[UIView animateWithDuration: 1.5
animations: ^(void)
{
//As an example i just called them button1, button2, etc.
self.button1.alpha = 1;
self.button2.alpha = 1;
self.button3.alpha = 1;
self.button4.alpha = 1;
self.button5.alpha = 1;
}
];
I included the above as an example of what I am asking. Is there a way to put all the buttons in an NSDictionary and write one line (where the buttons are currently located) that changes all of their alphas?
The preferred mechanism nowadays for buttons you've added in Interface Builder would be an IBOutletCollection:
#property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *buttons;
Clearly, in Interface Builder you would connect the individual buttons to the outlet collection. For a discussion of IBOutletCollection, see NSHipster's IBAction / IBOutlet / IBOutlet​Collection article.
If you're not using Interface Builder, but rather have created these buttons programmatically, you could just have an NSArray:
#property (strong, nonatomic) NSArray *buttons;
Which you'd then populate yourself:
self.buttons = #[self.button1, self.button2, self.button3, self.button4, self.button5, self.button6];
Regardless of how you build this array (either outlet collection or manually populated), you can then iterate through that array as you update a property of the buttons:
for (UIButton *button in self.buttons) {
button.alpha = 1;
}
Or, even simpler, you can update all of them with setValue:forKey::
[self.buttons setValue:#1 forKey:#"alpha"];
You can use button tags to accomplish this. Set the same tag for multiple buttons (your groups) and do:
button.tag = 1;
then:
for (UIButton *btn in button) {
if(btn.tag == 1)
{
// do something
break; // don't need to run the rest of the loop
}
}

UIScrollView not scrolling when adding UIButtons as subviews

I'm trying to build a simple UIScrollView with paging to horizontally scroll between 3 images.
The tricky part is that I would like that each image would be clickable and catch the click event.
My technique is to create 3 UIButtons that each consists UIImage. give each button a tag and set an action.
Problem: I can catch the click event - BUT it's not scrollable!
Here is my code:
- (void) viewDidAppear:(BOOL)animated {
_imageArray = [[NSArray alloc] initWithObjects:#"content_01.png", #"content_02.png", #"content_03.png", nil];
for (int i = 0; i < [_imageArray count]; i++) {
//We'll create an imageView object in every 'page' of our scrollView.
CGRect frame;
frame.origin.x = _contentScrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = _contentScrollView.frame.size;
//
//get the image to use, however you want
UIImage* image = [UIImage imageNamed:[_imageArray objectAtIndex:i]];
UIButton* button = [[UIButton alloc] initWithFrame:frame];
//set the button states you want the image to show up for
[button setImage:image forState:UIControlStateNormal];
[button setImage:image forState:UIControlStateHighlighted];
//create the touch event target, i am calling the 'productImagePressed' method
[button addTarget:self action:#selector(imagePressed:)
forControlEvents:UIControlEventTouchUpInside];
//i set the tag to the image #, i was looking though an array of them
button.tag = i;
[_contentScrollView addSubview:button];
}
//Set the content size of our scrollview according to the total width of our imageView objects.
_contentScrollView.contentSize = CGSizeMake(_contentScrollView.frame.size.width * [_imageArray count], _contentScrollView.frame.size.height);
_contentScrollView.backgroundColor = [ENGAppDelegate backgroundColor];
_contentScrollView.delegate = self;
}
Well, since UIButton is an UIControl subclass, it "eats up" the touches of your scroll view:
[UIScrollView touchesShouldCancelInContentView:] The default returned value is YES if view is not a UIControl object; otherwise, it returns NO.
(from https://developer.apple.com/library/ios/documentation/uikit/reference/UIScrollView_Class/Reference/UIScrollView.html#//apple_ref/occ/instm/UIScrollView/touchesShouldCancelInContentView:)
You could influence this by subclassing UIScrollView and overwriting touchesShouldCancelInContentView: (and/or touchesShouldBegin:withEvent:inContentView:). However, for your use case I'd not use buttons in the first place. Why not just add a tap gesture recognizer to the scrollview and use the touch point to determine which image has been tapped? That's much easier and should work without any issues.
This completely solved this issue for me:
scrollview.panGestureRecognizer.delaysTouchesBegan = YES;
Credit goes to https://stackoverflow.com/users/904365/kjuly for providing the right answer in this topic: ScrollView/TableView with UIControl/UIButton subviews not scrollable under iOS 8

IBOutletCollection objects indexed wrong

i have 10 uibuttons on story board and i've linked them with iboutletcollections. Then i set buttons backgroundimage from array of uiimage using loop. When i run my project button indexes differs from image indexes
Here is my code
-(void)setButtonImages
{
for (int i=0; i<imageArray.count; i++)
{
UIButton *b =[self.myButtons objectAtIndex:i];
[b setBackgroundImage:[imageArray objectAtIndex:i] forState:UIControlStateNormal];
}
}
create your buttons manually then tag them one by one and you can use your buttons with tag

ios- is "swapping" UIViews possible?

Here's my code:
if([pantallas objectForKey:par]){
UIView *vista= [[UIView alloc] initWithFrame:self.Botones.frame];
vista.backgroundColor= [UIColor brownColor];
CGSize la= CGSizeMake(50,60);
int cuantos= [part2 count];
NSArray *arr= [COLGenerales tileN:cuantos RectsOfSize:la intoSpaceOf:vista.frame withMaxPerRow:5 spaceVertical:10 spaceHorizontal:10];
for(int j=0; j<cuantos; j++){
UIButton *bot= [[UIButton alloc] initWithFrame:[[arr objectAtIndex:j] CGRectValue]];
bot.tag=j;
bot.titleLabel.text=par;
bot.titleLabel.hidden=true;
bot.imageView.image = [UIImage imageNamed:[[part2 allKeys] objectAtIndex:j]];
[bot addTarget:self action:#selector(registrar:) forControlEvents:UIControlEventTouchDown];
[vista addSubview:bot];
}
[pantallas setObject:vista forKey:par];
self.Botones= vista;
}else{
self.Botones= [pantallas objectForKey:par];
}
Botones is a simple view embedded into the view this class controls (first initiated by the Nib file), the class method of COLGenerales returns an array of CGRects coded as NSValues, and registrar: is a local method.
Everything gets properly set (I've thoroughly checked this with the debugger). The view gets successfully created, set, and added to the dictionary.
However, I absolutely never get the actual screen to change. I even included the background color change just to check if it isn't some kind of problem with the buttons. Nothing. Any suggested solution to this?
A property that is an IBOutlet does not have an intrinsic connection to the view hierarchy—it only makes it possible to populate that property from a xib. When you set self.Botones, you'll need to do something like the following:
[self.Botones removeFromSuperview];
self.Botones = newValue;
[self.BotonesSuperview addSubview:self.Botones];
If you update self.Botones in many places, and you always want the change reflected on-screen, you could add this into a setter implementation:
-(void)setBotones:(UIView*)newValue {
if (newValue != _Botones) {
[_Botones removeFromSuperview];
_Botones = newValue;
[self.BotonesSuperview addSubview:_Botones];
}
}
I recommend using a UINavigation controller that houses these two views.
You can reference this link Swapping between UIViews in one UIViewController
Basically, you create one view, removeSubview for the first and then add the second one with addSubview!
[view1 removeFromSuperview];
[self.view addSubview: view2];
Other reference sources:
An easy, clean way to switch/swap views?
How to animate View swap on simple View iPhone App?
Hopefully this helps!

iOS: Moving a uibutton by its tag outside of where it was generated

Is it possible? I have an array of buttons created in an void and I want to move one when a neighbouring one is called in the buttonTapped void. I have no trouble moving the button thats pressed because it is the sender, but I also need to move the one next to it and can't seem to get it to move. Each button in the array has a tag value so they're unique.
Thanks
Reasonable intuitive assumption: you generated the buttons so that they are ordered in the array...
- (void)moveButton:(UIButton *)sender // whatever
{
NSUInteger idx = [buttonArray indexOfObject:sender] + 1;
UIButton *nextButton = idx < buttonArray.count ? [buttonArray objectAtIndex:idx] : nil;
// do something with `nextButton`
}

Resources