Check button backgroundColor in if statement - ios

I'm trying to set if condition on the basis of button background color. I've found a solution on stackoverflow but it's not for me because what I'm doing different is my buttons are in an array and if condition is in a for loop. It's like checking all the buttons in the array every time a button is tapped and if any button have background color as black don't show the next interface.
This method is setting those color which is doing good.
for (int i=0; i<10; i++)
{
[buttonsArray[i] setColor:[UIColor blackColor]];
}
Now the problem is in this method:
-(void)myFunction
{
for (int i=0; i<10; i++)
{
if([buttonsArray[i] backgroundColor:[UIColor blackColor]])
{
//code I want to use if the condition is true
}}}
I've also tried the following conditions in if:
if([buttonsArray[i].backgroundColor isequal:[UIColor blackColor]])
//or
if([[buttons[i] background] isEqual:myBlack])
//or
if([buttonsArray[i] backgroundColor]==[UIColor blackColor])
Please not that I'm using setColor to set the color not setBackgroundColor and I want to keep it that way because this is a requirement.

You shouldn't be using the colour of the button, you should have another array which contains an NSNumber (or a custom class) that holds the state of each button. This will be easy to use and test. Trying to use the UI to hold your model state will always lead to issues like this.

Instead of checking button using color, go for Tags.
Use tags to set a specific numeric id for a button and you can use the same throughout the code. Like this,
myButton.tag=1;
myButton.tag=2;
OR
for (int i=0; i<10; i++)
{
[buttonsArray[i] setTag:i];
}
or you can set tag in interface builder properties of button.

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

Keeping track of objects on the screen

Even though I’m writing in Objective C, most of my code is still written in a procedural style. However, now I want to do something where that approach will not work. So I need some advice on how to deal with an indeterminate number of objects on the screen at the same time. I’m sure that this problem has been solved, I just haven’t been able to find out how.
I have a bunch of games where I put two or four pictures on the screen and then the user interacts with the picture. When they are done with a page they swipe to the next one and I use a transition to slide the pictures off the screen. I can control the movement of the pictures because when they were created I name them self.picture_1 and self.picture_2. The movement method knows about them even though that method didn’t create them.
Now suppose I want to have an indeterminate number of pictures on the screen. I can’t call them self.picture_1. through self.picture_n because ObjectiveC won’t let you dynamically create variable names. But I still need to move them in a method where they weren’t created.
I can make it work with two techniques, neither of which seem ideal. First, I look at all the objects on the screen and then do something with the ones that I want to target. Note: pictures are in buttons.
for ( id subview in self.parentView.subviews ) {
if ( [subview isKindOfClass:[UIButton class]] ) {
UIButton *pictureButton = subview;
for (NSUInteger i=0; i<self.totalItems; i++) {
NSUInteger row = (i % 2) + 1;
NSUInteger column = (i/2) + 1;
NSString *pictureTitle = [NSString stringWithFormat:#"pictureR%iC%i", row, column];
if ( [pictureButton.titleLabel.text isEqualToString:pictureTitle] ) [pictureButton removeFromSuperview];
}
}
}
This works for removing them from the view, but gets cumbersome when I try to make the pictures slide off the screen.
The second way is to make an array that holds the picture objects when they are created. I’ve been playing with something like this.
self.gridImages = [NSMutableArray arrayWithCapacity:4];
for (NSUInteger i = 0; i < itemsOnScreen; i++) {
Word *word = [wordListArray objectAtIndex:i];
self.gridImages[i] = word.image;
}
And then to do things with the pictures I loop through the array.
for (NSUInteger i = 0; i < itemsOnScreen; i++) {
Picture *picture = self.gridImages[i];
// do something with picture
}
Neither of these methods seems ‘right’ so I’m wondering if there is a preferred method for manipulating an indeterminate number of objects on the screen?
#Hot Licks, that works, so I put you answer into an answer.
I have it working for checkBoxes. They are created by the main view controller and it passes in a tag. I'm using tags starting at 1000 for checkboxes, 2000 for pictures, etc. Just before I put the checkBox on the screen, I assign it the tag.
[self.checkBox setTag:checkBoxTag];
You could also use: self.checkbox.tag = checkBoxTag;
When it is time to remove the checkBoxes, I loop through all of the tags starting at 1000 up to the total number of items on the screen. I have warnings turned up to 11 so I need to cast the counter to an NSInteger.
- (void)removeCheckboxes {
for (NSUInteger i = 0; i < self.totalItems; i++) {
NSInteger tagNumber = 1000 + (NSInteger)i;
[ [self.parentView viewWithTag:tagNumber] removeFromSuperview];
}
}

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

Change UISegmentedControl selected index or value programmatically

I have a UISegmentedControl with two segments (index: 0 and 1) that I am trying to reset programmatically to 0. When I run the command below it does not reset the segment index to 0 as expected. Instead it highlights segment indexed 1.
[seg setSelectedSegmentIndex:0];
Oddly when I log the selected segment, it returns 0.
NSLog(#"seg setSelectedSegmentIndex %d", seg.selectedSegmentIndex);
Also oddly, after running setSelectedSegmentIndex:0 I cannot reselect segment 0 manually by touch, it seems to be locked to segment 1, until I tap 1 wherein it works as normal.
Here is the setup for the button:
itemArray = [NSMutableArray arrayWithObjects: #"Zero", #"One", nil];
seg = [[UISegmentedControl alloc] initWithItems:itemArray];
[seg setFrame:segRect];
seg.segmentedControlStyle = UISegmentedControlStyleBar;
seg.momentary = NO;
[seg addTarget:self action:#selector(someAction:) forControlEvents: UIControlEventValueChanged];
[mainView addSubview:seg];
NOTE: To restate what I was trying to accomplish with this question: I want to set a UISegmentedControl's selected index via a variable dynamically, get the appropriate visual feedback, and check the selected index in a method, to make something happen depending on the selected index. See my answer below for a solution.
Change in viewDidLoad:
[seg setSelectedSegmentIndex:index];
you change use the index value as your wish.
From code, you can just do seg.selectedSegmentIndex = someDefaultIndex.
Whether you should set it in viewDidLoad: or not depends entirely on the structure of your application. For example, if your app is starting up and loading the view for the first time and needs to set the control to whatever value it had during the previous run of the app, then it definitely makes sense to do it there.
Swift 3.0
segmentedControl.selectedSegmentIndex = #your value#
The correct answer is the #arcady bob one at this link.
I have posted an updated version for Swift 5, which I quote here:
yourSegmentedControl.selectedSegmentIndex = 0
yourSegmentedControl.sendActions(for: UIControl.Event.valueChanged)
If you use just the first line, the segmented will react accordingly graphically, but your IBAction associated with the segmented control won't be called. In a few words: the second line is like tapping on the segmented control. This is what I needed and what I was missing.
This helps sort the selected segment, in terms of the visual feedbak, that is after programatically setting the selected segment this will tint the segments properly.
for (int i=0; i<[seg.subviews count]; i++)
{
if ([[seg.subviews objectAtIndex:i] respondsToSelector:#selector(isSelected)] && [[seg.subviews objectAtIndex:i]isSelected])
{
[[seg.subviews objectAtIndex:i] setTintColor:[UIColor grayColor]];
}
if ([[seg.subviews objectAtIndex:i] respondsToSelector:#selector(isSelected)] && ![[seg.subviews objectAtIndex:i] isSelected])
{
[[seg.subviews objectAtIndex:i] setTintColor:[UIColor blackColor]];
}
}
To restate what I was trying to accomplish with this question: I want to set a UISegmentedControl's selected index via a variable dynamically, get the appropriate visual feedback, and check the selected index in a method, to make something happen depending on the selected index.
Originally I guessed that this is as simple as: mySegmentedController.selectedSegmentIndex = someIndex, then test for the index. But as stated in my question, it was not working for me. The behavior is odd. After running that code the appropriate button would not highlight.
Here is a project where I did fix it, so it works. Not sure exactly why it works. Possibly a delay I put in there, before setting the index. I will update and comment the project file if I can refine it.
http://owolf.net/uploads/StackOverflow/SegmentedControllers.zip
WARNING: This is not quite answering the question, but is closely related.
I had a similar issue. Most of the time my UISegmentedController worked fine. It has 4 segments, Off, 30, 60 and 120.
At random intervals (normally just prior to a release!!), the Off segment becomes un-selectable from the user interface. (I didn't try selecting it from code because that is not what I need to do and won't solve my problem.)
The solution is to delete that UISegmentedController from my XIB and replace it with a fresh (and exactly identical) one which then works fine.
I even CMD-C and CMD-V'd the offending UISegmentedController into another App's XIB. And the Off segment (i.e the one at index 0) was un-selectable in that XIB too.
This seems to be an issue with XCode.

Resources