Deselect all UIButtons when selected

I will try to explain this the best that I can, so naked with me. I have eight (8) UIButtons settings in my game. When one is selected, it shows that it is selected, and if you click it again, it will be displayed as unselected. However, I want to make it so that when you select a button and select any of seven (7), they become inaccessible.

I know how to do this with [buttonName setSelected:NO] , but the problem is that I cannot pass buttonOne to buttonTwo if buttonTwo is already passed to buttonOne because I already imported the buttonTwo header file into buttonOne. It throws a parsing error if I have both headers importing each other. I lingered on this for some time and hoped that someone could solve my problem.

Thanks for any help.

+6
source share
9 answers

In fact, I created the answer by reading all of your guys, whom I really thank. The tag property of the UIButton class was unknown to me before this post.

I created my own subclass of UIButton, called him CustomUIButton.m . I created an NSMutableArray property to use when saving buttons, which I will call customButtonArray .

When I created the button, I set the tag property and added the button to the local array on the parent view controller. After all the buttons that I wanted were created, I set customButtonArray , for example:

 // Initialize buttonHolderArray NSMutableArray *buttonHolderArray = [[NSMutableArray alloc] init]; // Create a button CustomUIButton *newButton = [[CustomUIButton alloc] initWithFrame:CGRectMake(10, 10, 50, 30)]; newButton.tag = 1; [newButton setImage:[UIImage imageNamed:@"newButtonUnselected" forControlState:UIControlStateNormal]]; [buttonHolderArray addObject:newButton]; // Create additional buttons and add to buttonHolderArray... // using different numbers for their tags (ie 2, 3, 4, etc) // Set customButtonArray property by iterating through buttonHolderArray NSInteger buttonCount = [buttonHolderArray count]; for (int i = 0; i < buttonCount; i++) { [[buttonHolderArray objectAtIndex:i] setCustomButtonArray:buttonHolderArray]; } 

To deselect any other button selected when calling the various handleTap: buttons, I repeated using customButtonArray in the main subclass file and set the selected property to NO . I also set the correct image from another property of the array, which I manually filled with images, so that I would not have to fill the array every time I click the button. At the end, all other buttons were not selected, for example:

 // Populate two arrays: one with selected button images and the other with // unselected button images that correspond to the buttons index in the // customButtonArray NSMutableArray *tempSelectedArray = [[NSMutableArray alloc] init]; [tempSelectedArray addObject:[UIImage imageNamed:@"newButtonSelected"]]; // Add the other selected button images... // Set the property array with this array [self setSelectedImagesArray:tempSelectedArray]; NSMutableArray *tempUnselectedArray = [[NSMutableArray alloc] init]; [tempUnselectedArray addObject:[UIImage imageNamed:@"newButtonUnselected"]]; // Add the other unselected button images... // Set the property array with this array [self setUnselectedImagesArray:tempUnselectedArray]; - (void)handleTap:(UIGestureRecognizer *)selector { // Get the count of buttons stored in the customButtonArray, use an if-elseif // statement to check if the button is already selected or not, and iterate through // the customButtonArray to find the button and set its properties NSInteger buttonCount = [[self customButtonArray] count]; if (self.selected == YES) { for (int i = 0; i < buttonCount; i++) { if (self.tag == i) { [self setSelected:NO]; [self setImage:[[self unselectedImagesArray] objectAtIndex:i] forControlState:UIControlStateNormal]; } } } else if (self.selected == NO) { for (int i = 0; i < buttonCount; i++) { if (self.tag == i) { [self setSelected:NO]; [self setImage:[[self selectedImagesArray] objectAtIndex:i] forControlState:UIControlStateNormal]; } } } for (int i = 0; i < buttonCount; i++) { if (self.tag != i) { [self setSelected:NO]; [self setImage:[[self unselectedImagesArray] objectAtIndex:i] forControlState:UIControlStateNormal]; } } } 

Thank you for all the useful information, although I suppose I should share the final answer, which I examined in detail to help someone else who is facing this problem.

+1
source

Get the parent view of the current button and iterate over all the buttons inside without selecting all of them. Then select the current one.

 // Unselect all the buttons in the parent view for (UIView *button in currentButton.superview.subviews) { if ([button isKindOfClass:[UIButton class]]) { [(UIButton *)button setSelected:NO]; } } // Set the current button as the only selected one [currentButton setSelected:YES]; 

Note As suggested in the comments, you can store an array of buttons and iterate over them in the same way as the previous code with subzones of the parent view does. This will improve the performance of your code if there are many other routines inside the view containing the buttons.

+12
source

I know that it is too late to answer this question, but I did this only in small lines of code. Here is what I did:

 NSArray *arrView = self.view.subviews; for (UIButton *button in arrView) { if ([button isKindOfClass:[UIButton class]]) { [((UIButton *) button) setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; } } [button1 setTitleColor:[UIColor orangeColor] forState:UIControlStateNormal]; 
+2
source

An easy way to do it.

 -(void)buttonSelected:(id)sender{ UIButton *currentButton = (UIButton *)sender; for(UIView *view in self.view.subviews){ if([view isKindOfClass:[UIButton class]]){ UIButton *btn = (UIButton *)view; [btn setSelected:NO]; } } [currentButton setSelected:YES]; } 
+2
source

The easiest way here is to get the parent UIView button and enable it. Here is a quick example from my code:

 for (UIView *tmpButton in bottomBar.subviews) { if ([tmpButton isKindOfClass:[UIButton class]]) { if (tmpButton.tag == 100800) { tmpButton.selected = YES; [tmpButton setTitleColor:[UIColor greenColor] forState:UIControlStateNormal]; [tmpButton setTitleColor:[UIColor greenColor] forState:UIControlStateHighlighted]; }else{ tmpButton.selected = NO; [tmpButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal]; [tmpButton setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted]; } } } 
0
source

Reply "It throws a parsing error if I have both headers importing each other" ...

You should refrain from using #import in .h files as much as possible and instead declare what you want to use as a direct class declaration:

 @class MyCustomClass @interface SomethingThatUsesMyCustomClass : UIViewController @property (nonatomic, strong) MyCustomClass *mcc; @end 

Then the #import header in your .m file:

 #import "MyCustomClass.h" @implementation SomethingThatUsesMyCustomClass -(MyCustomClass *)mcc { // whatever } @end 

This approach will prevent errors caused by #import loops.

Although I have to say that I agree with SergiusGee's comment on the question that this setting is a bit strange.

0
source

I figured out a pretty simple way to solve this problem. My example is for 2 buttons, but you can easily add extra if statements for extra buttons. Connect all the buttons to the .h file as properties and name them (I made buttons1 and button2). Put the following code in your .m file and connect it (via the storyboard) to all of your buttons. Make sure that when you customize your button to set the image for BOTH, the usual UIControlStateNormal and UIControlStateSelected, or this will not work.

 - (IBAction)selectedButton1:(id)sender { if ([sender isSelected]) { [sender setSelected:NO]; if (sender == self.button1) { [self.button2 setSelected:YES]; } if (sender == self.button2) { [self.button1 setSelected:YES]; } } else { [sender setSelected:YES]; if (sender == self.button1) { [self.button2 setSelected:NO]; } if (sender == self.button2) { [self.button1 setSelected:NO]; } } 
0
source

Have you tried using the ReactiveCocoa framework and adding some blocks for your code, this is not the easiest approach, but I would say that it is most effective when you have several dependencies and is very useful for scaling

I created a small project to solve your problem using my proposed approach (I tried to adapt it to the old old MVC model instead of my preferred MVVM)

you can find it here

https://github.com/MWaly/MWButtonExamples

be sure to install the cocoa pods file, since we need “ReactiveCocoa” and “BlocksKit” for this sample

we will use two main classes

ViewController => A viewController object that displays the MWCustomButton buttons => Custom UIButton that handles events

when creating buttons, a weak link to the viewController is also created using the property

 @property (weak) ViewController *ownerViewController ; 

events will be processed using the blocksKit bk_addEventHandler method and pass it to the ViewController (selectedButtonCallBackBlock)

  [button bk_addEventHandler:^(id sender) { self.selectedButtonCallBackBlock(button); } forControlEvents:UIControlEventTouchUpInside]; 

now in the ViewController for each button pressed, callBackButtonBlock will be a trigger, where it will change the currently selected button, if applicable

 __weak __typeof__(self) weakSelf = self; self.selectedButtonCallBackBlock=^(MWCustomButton* button){ __typeof__(self) strongSelf = weakSelf; strongSelf.currentSelectedButton=button; }; 

in the MWCustomButton class, he will listen for any changes in the "currentSelectedButton" property of his owner ViewController and will change his selection property to match it using our good Reactive cocoa

  ///Observing changes to the selected button [[RACObserve(self, ownerViewController.currentSelectedButton) distinctUntilChanged] subscribeNext:^(MWCustomButton *x) { self.selected=(self==x); }]; 

I think this will solve your problem, again your question can be solved in a simpler way, however I believe that using this approach would be more scalable and cleaner.

0
source

Scroll through all the views in the parent view. Check if it is a UIButton (or your custom button class) and not the sender. Set all isSelected views to false. Once the loop is complete, set the sender button isSelected to true.

Swift 3 way:

 func buttonPressed(sender: UIButton) { for view in view.subviews { if view is UIButton && view != sender { (view as! UIButton).isSelected = false } } sender.isSelected = true } 
0
source

Source: https://habr.com/ru/post/952978/


All Articles