iOS: setting alphas of multiple buttons at once - ios

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
}
}

Related

Make changes to a number of buttons programatically

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];

Loop in a variable of type IBOutlet

I have twelve text fields as you can see below:
IBOutlet UITextField *ce_1;
IBOutlet UITextField *ce_2;
IBOutlet UITextField *ce_3;
....
IBOutlet UITextField *ce_12;
All I have to do is to set an existing object in an array in each of the variables that are responsible for the text fields, I'm currently doing as follows:
ce_1.text = myArray[1];
ce_2.text = myArray[2];
ce_3.text = myArray[3];
....
ce_12.text = myArray[12];
Not to be writing a lot, I thought I'd put this in an automated way within a loop as follows:
for(i=1;i<13;i++){
ce_[i].text = myArray[i];
}
But this command does not work the way I expected, so I would like your help to try to solve my idea and put it into practice, is there any way of doing this?
Research and start using IBOutletCollection. It will give you an array of text fields that you can build in your storyboard XIB.
Note that you may need to consider the order of the array, and that you might want to sort it (possibly based on the tag of each view).
Technically, you could use string formats and KVC to do what you're currently trying to but it is far from ideal.
You can't just replace ce_1 ce_2 ce_3 with ce_[i] it doesn't work that way. You can only use [number] with an nsarray variable (or decendents).
for example:
NSArray* myArray = #[#1];
NSLog(#"%#", myArray[0]);
You might want to look into IBOutletCollection in order to achieve something similar to what you're looking for.
However, contrary to other answers here IBOutletCollection are ordered by how you link them in the interface builder.
Refer to this for IBOutletCollections: How can I use IBOutletCollection to connect multiple UIImageViews to the same outlet?
You can use IBOutletCollection. You can also use key-value coding:
for(NSUInteger i = 0; i < 13; i++)
{
[[self valueForKey:[NSString stringWithFormat:#"ce_%u", i]] setText: myArray[i]];
}
This will give you what you want.
The way I like to handle these situations is creating a temporary array containing all the text fields:
NSArray *allFields = #[_ce_1, _ce_2, _ce_3, ...];
NSInteger i = 0;
for (UITextField *tf in allFields)
{
tf.text = myArray[i];
i++
}
IBOutletCollection also work but sometimes it gets hard to figure out when you come back to your project which label is #3 or #5 and such... I find this works better for me usually :)

Hide dynamically created UILabels in IBAction

I have declared UILabel in ViewController first like this:
#property (weak, nonatomic) IBOutlet UILabel *answerLabel;
Then I have created label in a loop:
//creating answer labels
i = 0;
int y=200;
while (i < numberOfAnswers) {
UILabel *answerLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, y, 300, 20)];
answerLabel.text = [NSString stringWithFormat:#"%# (%#)", questionBank[randomQuestionNumber][1][i][0],questionBank[randomQuestionNumber][1][i][1]];
answerLabel.hidden=NO;
[self.view addSubview:answerLabel];
i++;
y = y + 20;
}
In the IBAction I have this but it doesn't work. Any ideas where the mistakes is?
- (IBAction)nextQuestion:(id)sender {
//hiding labels
self.answerLabel.hidden=YES;
}
I would suggest first create view and then add those labels in this view.
Now when you need to hide, just hide this view.
Hope this answer.
For what you are doing, it is lengthy way. First white creating label you have to set tag. Then for hiding, again get label by tag and then hide accordingly.
Your code contains lots of issues.
First of all, when you are talking about multiple outlets, in the declaration it should be outletCollection like this:
#property (strong, nonatomic) IBOutletCollection(UILabel) NSArray *answerLabels;
Again, as you are creating your labels dynamically, you just can't add them in your IBOuletCollection.
#FahimParkar is suggesting a good approach. But as you might need to work with individual labels, you might use following approach..
First declare an array of labels like this:
#property (strong, nonatomic) NSMutableArray *answerLabels;
Now when you are creating the label, alloc your array & add new labels in it like this:
i = 0;
int y=200;
self.answerLabels= [[NSMutableArray alloc]init]
while (i < numberOfAnswers) {
UILabel *answerLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, y, 300, 20)];
answerLabel.text = [NSString stringWithFormat:#"%# (%#)", questionBank[randomQuestionNumber][1][i][0],questionBank[randomQuestionNumber][1][i][1]];
answerLabel.hidden=NO;
[self.view addSubview:answerLabel];
[self.answerLabels addObject:answerLabel]
i++;
y = y + 20;
}
Now when you want to hide a particular label, you can do this by referring anyone of these three:
Array index.
labelText.
add tag for your label as suggested by Fahim & refer to it.. :)
Let me know if more info needed.. :)

How do I use a UIButton to change a label multiple times?

I want to have one UIButton that will change the text of a label in a series. For example, I may have a label that says hello.
Then when i push a button, it will change to, What's up?.
But then a second tap of the same button will change the label to Nuttin' much!.
I know how to make the text of a label change once, but how do I change it many times with the same button? Preferably, anywhere around 20 to 30 separate texts.
Thank you in advance! :D
That's pretty open ended. Consider adding a property to your class which is an index into an array of strings. Each time you push the button increment the array (modulo size of array) and use the corresponding string to update the button. But there are a lot of other ways you could do this...
What happens when the app runs out of phrases? Start over? The typical approach would look like this.
#property (strong, nonatomic) NSArray *phrases;
#property (assign, nonatomic) NSInteger index;
- (IBAction)pressedButton:(id)sender {
// consider doing this initialization somewhere else, like in init
if (!self.phrases) {
self.index = 0;
self.phrases = #{ #"hello", #"nuttin' much" }; // and so on
}
self.label.text = self.phrases[self.index];
self.index = (self.index == self.phrases.count-1)? 0 : self.index+1;
}
In the viewDidLoad method, create an array with strings to hold the labels. Then create a variable to keep track of which object should be set as the current label. Set the initial text:
NSArray *labelNames = [[NSArray alloc] initWithObjects:#"hello",#"what's up?", #"nuttin much"];
int currentLabelIndex = 0;
[label setText:[labelNames objectAtIndex:currentLabelIndex]];
Then in the method that gets called when the button is tapped, update the text and the index.
- (IBAction) updateButton:(id)sender {
// this finds the remainder of the division between currentLabelIndex+1 and labelNames.count. If it is less than the count, its just the index. If its equal to the count we go back to the beginning of the array.
currentLabelIndex = (currentLabelIndex+1)%labelNames.count;
[label setText:[labelNames objectAtIndex:currentLabelIndex]];
}

How to access multiple buttons in access function?

I have two buttons in each row of a tableview. One is labeled "have it" the other "want it" Each button starts off at 20% opacity when the app starts. When one button is tapped the opacity is set to 100% . I need logic so that if one button is set to 100% opacity and the other one set at 20% is tapped, the first button needs to be set to 20% and the second button to 100% (so the opacity needs to be reversed).
Each button has it's own action that is run when pressed. I can access the button that is pressed and set the opacity with (UIButton *senderButton = (UIButton *)sender). However I need to set the opacity of the other button as well. How can access the other button (the one that was not pressed) inside of my action/function that is called when one is pressed? Thanks!
You can create an outlet for each button. So that you can set its property from any where within its container class.
if I correct understand your question, you can declare your buttons in header-file like this:
#interface myController : UIViewController
{
UIButton *b1;
UIButton *b2;
}
tmen in m-file (in viewDidLoad) you can set this buttons with one selector and different tags: (for more information about creation buttons: How do I create a basic UIButton programmatically?)
-(void)viewDidLoad
{
[super viewDidLoad];
b1 = [UIButton buttonwithType:UIButtonTypeCustom];
[b1 addTarget:self withAction:#selector(clickINMyButtons:) forState:UIControlTouchUPInside]; // sorry, I don't remember correct syntax, i'll correct this some later if you needed in it.
b1.tag = 1;
b1.frame = CGRectMake(0,0,12,12); //example
[self.view addSubView:b1];
}
alike declare b2 with different:
b2.tag = 2;
So, then you implement your selector with changing opacity:
-(void)clickINMyButtons:(UIButton *)sender
{
if (sender.tag == 1)
{
sender.alpha = 1; // or b1.alpha = 1;
b2.alpha = 0.2;
}
else if (sender.tag == 2)
{
sender.alpha = 1; // or b2.alpha = 1;
b1.alpha = 0.2;
}
}

Resources