I am working on an app where I have multiple buttons on one page that you click on to go to a different view. The thing is I would like the user to click on them in a specific order. So basically, have all buttons locked except for one and then each time you click on a button that is enabled, it unlocks a new one.
Thanks.
You can do this easily via Tag
When you creating view at that time just put FirstButton in Enabled mode.
OnClick event on every UIButton you can Enabled next one.
For example
i created View with 4 UIButton and given tag 1,2,3,4 at ViewLoad only UIButton with Tag 1 is only Enabled
For all 4 UIButton i have created common Action method as follow which Enabled next UIButton with next Tag
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if([[NSUserDefaults standardUserDefaults] valueForKey:#"LastEnableButton"]){
UIButton * btnTemp = (UIButton *) [self.view viewWithTag:[[[NSUserDefaults standardUserDefaults]valueForKey:#"LastEnableButton"] intValue]];
[btnTemp setEnabled:YES];
NSLog(#"If you want to enable all button which are enabled previously then make for loop up to NSUserDefaults value from starting value");
}
}
- (IBAction)btn_click : (id)sender {
UIButton * btnTemp = (UIButton *) [self.view viewWithTag:([sender tag] + 1)];
if(btnTemp) {
if([btnTemp isKindOfClass:[UIButton class]]) {
[btnTemp setEnabled:YES];
[[NSUserDefaults standardUserDefaults]setValue:[NSNumber numberWithInt:([sender tag] + 1)] forKey:#"LastEnableButton"];
[[NSUserDefaults standardUserDefaults]synchronize];
}
}
}
Related
I have made a custom cell.In each custom cell there are many button like 3 to 4 i want add tap gesture for each button inside that cell.So that i can uniquely identify which cell's button was clicked.I have searched a lot but didn't find any good solution.
Please tell.
you want to access the button you can directly access, no need of Gesture
do like
[yourButton1 addTarget:self action:#selector(selectButtonPressed1:) forControlEvents:UIControlEventTouchUpInside];
yourButton1.tag=indexPath.row;
[yourButton2 addTarget:self action:#selector(selectButtonPressed2:) forControlEvents:UIControlEventTouchUpInside];
yourButton2.tag=indexPath.row;
[yourButton3 addTarget:self action:#selector(selectButtonPressed3:) forControlEvents:UIControlEventTouchUpInside];
yourButton3.tag=indexPath.row;
[yourButton4 addTarget:self action:#selector(selectButtonPressed4:) forControlEvents:UIControlEventTouchUpInside];
yourButton4.tag=indexPath.row;
Method - 1
-(void)selectButtonPressed1:(UIButton*)sender
{
NSLog(#"selcted button1");
}
Method - 2
-(void)selectButtonPressed2:(UIButton*)sender
{
NSLog(#"selcted button2");
}
Method - 3
-(void)selectButtonPressed3:(UIButton*)sender
{
NSLog(#"selcted button3");
}
Method - 4
-(void)selectButtonPressed4:(UIButton*)sender
{
NSLog(#"selcted button4");
}
Lets say you have n number of buttons. And you have one butotn action method:
YOu need to connect this method to all of your n buttons (touch up inside), so that whenever you press a button, this method will get hit.
You can either give tag values for your buttons or you can recognise them by thier title
-(IBAction) nButtonActions:(id)sender{
if([[sender titleLabel] isEqualtoString:#"your button-1 title"]){
//call your method for button -1
}
//or you can do the same using sender.tag
}
use restoration identifier.
button.restorationIdentifier = #"Cell Number _ button tag";
for example
button.restorationIdentifier = [NSString stringWithFormat:#"%#", indexPath.row];
NSString* rowIndexStr = ((UIButton*)sender).restorationIdentifier;
I have a check box designed through a button and i am able to change the checkbox images but i am unable to save that last image that is checked in the checkbox when i click on Save button.
I have a page in which a check box is there and save button action is also there when i click on save the value in the checkbox must be saved and when i again re-enter in that screen the previous whatever the value in the checkbox must be seen, but for me every time when i enter into this screen the checkbox is seen empty.
Hope someone helps me out.
BOOL checked;
- (IBAction)canFollowAction:(id)sender
{
UIButton *tappedButton = (UIButton*)sender;
if([tappedButton.currentImage isEqual:[UIImage imageNamed:#"checkBox.png"]])
{
[sender setImage:[UIImage imageNamed:#"selected.png"] forState:UIControlStateNormal];
}
else
{
[sender setImage:[UIImage imageNamed:#"checkBox.png"]forState:UIControlStateNormal];
}
}
- (IBAction)btnSaveAction:(id)sender
{
if(checked)
{
[btnCheckCanFollow setImage:[UIImage imageNamed:#"selected.png"] forState:UIControlStateNormal];
}
else
{
[btnCheckCanFollow setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
}
[self.navigationController popViewControllerAnimated:YES];
[[[iToast makeText:#"Successfully Updated"]setGravity:iToastGravityBottom]show];
}
#kool kims - The term you used Save value. There any many ways to keep persistent data of your application.
Use NSUserDefaults to save values at application level.
Use .plist file
CoreData
SQlite
Document directory
As per your application architecture you can choose from above, which is more relevant and efficient for your application.
EDIT:
The simplest way if there are not more than one checkbox, You can use NSUserDefaults
Save check value when you click on Save button
- (IBAction)btnSaveAction:(id)sender
{
NSNumber *checkValue = [NSNumber numberWithBool:checked];
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
[standardDefaults setObject:checked forKey:#"kCheckBoxValue"];
[standardDefaults synchronize];
if(checked)
{
[btnCheckCanFollow setImage:[UIImage imageNamed:#"selected.png"] forState:UIControlStateNormal];
}
else
{
[btnCheckCanFollow setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
}
[self.navigationController popViewControllerAnimated:YES];
[[[iToast makeText:#"Successfully Updated"]setGravity:iToastGravityBottom]show];
}
Whenever you open that ViewController you get previous values from NSUserDefaults from -viewDidLoad or -viewWillAppear.
- (void)viewDidLoad {
[super viewDidLoad];
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
if ([standardDefaults objectForKey:#"kCheckBoxValue"]) {
NSNumber *checkValue = [standardDefaults objectForKey:#"kCheckBoxValue"];
checked = [checkValue boolValue];
} else {
checked = NO;
}
}
You Must Save the state in NSUSERDEFAULTS!
For Example ON Button Click
if (button.selected)
{
[button setSelected:YES];
[[NSUserDefaults standardUserDefaults]setObject:[NSNumber numberWithBool:YES] forKey:#"REMEMBER_ME"];
}
and check on ViewDidLoad
if([[NSUserDefaults standardUserDefaults] boolForKey:#"REMEMBER_ME"] == YES)
{
[button setSelected:YES];
[button setImage:[UIImage imageNamed:#"selected.png"] forState:UIControlStateSelected];
}
else
{
[button setSelected:NO];
[button setImage:[UIImage imageNamed:#"checkBox.png"] forState:UIControlStateNormal];
}
Take a global variable to strore the status of check box or in NSUserdefaults u can save the status of button. & chek this status on viewdidload method of controller.
According to what I understood Lets take an example
#property (weak, nonatomic) IBOutlet UIButton *yourButton;
and its Implementation Action
- (IBAction)yourMethodName:(UIButton *)sender {
int tag=_yourButton.tag; //if you have tagged your UI button save it to know which button has changed its state.
if(sender.isSelected){ //Checking state of the button whether selected or not.
UIImage *buttonImage=sender.currentImage;//save this image if your selected images randomly.
NSString *buttonText=sender.currentTitle;//gets you current text in button.
}else{
//selected state is NO
//checkBox is Off.
}
}
here I have showed how you can get different values you need only to store your state as I believe your working with one button/checkbox and you can populate your image based on that state.
However if you have multiple checkboxes or UIbutton you may want to Tag each UIButton your using
[_yourButton setTag:1];
and store tag value too inside action method using sender.tag
EDIT:
Just now went through your code
BOOL checked; value is never set or stored.
so everytime if condition fails.
Also If you have multiple UIButtons you may want to store checked state and tag for the UIButton as I have mentioned earlier;
I have a UIViewController with a bunch of buttons that each have a (unique) tag. I wrote the following method:
- (void) highlightButtonWithTag: (NSInteger) tag
{
UIButton *btn = (UIButton *)[self.view viewWithTag: tag];
btn.highlighted = YES;
}
What I am trying to do is have a bunch of buttons that each function like a toggle: when I tap one, it should be come active (i.e. highlighted) and the one that was highlighted before should become "un"highlighted.
When the view comes up, I use the viewDidAppear method to set the initial selection:
- (void) viewDidAppear:(BOOL)animated
{
self.selectedIcon = 1;
[self highlightButtonWithTag: self.selectedIcon];
}
And this seems to work just fine: when the view comes up, the first button is selected. However, when I try to update stuff through the #selector connected to the buttons, the previous button is "un"highlighted but the button with sender.tag doesn't get highlighted.
- (IBAction) selectIcon:(UIButton *)sender
{
// "Un"highlight previous button
UIButton *prevButton = (UIButton *)[self.view viewWithTag: self.selectedIcon];
prevButton.highlighted = NO;
// Highlight tapped button:
self.selectedIcon = sender.tag;
[self highlightButtonWithTag: self.selectedIcon];
}
What am I missing here?
The problem is that the system automatically highlights then unhighlights the button on touchDown and touchUp respectively. So, you need to highlight the button again, after it's unhighlighted by the system. You can do by using performSelector:withObject:afterDelay: even with a 0 delay (because the selector is scheduled on the run loop which happens after the system has done it's unhighlighting). To use that method, you have to pass an object (not an integer), so If you modify your code slightly to use NSNumbers, it would look like this,
- (void) highlightButtonWithTag:(NSNumber *) tag {
UIButton *btn = (UIButton *)[self.view viewWithTag:tag.integerValue];
btn.highlighted = YES;
}
- (void) viewDidAppear:(BOOL)animated {
self.selectedIcon = 1;
[self highlightButtonWithTag: #(self.selectedIcon)];
}
- (IBAction) selectIcon:(UIButton *)sender {
// "Un"highlight previous button
UIButton *prevButton = (UIButton *)[self.view viewWithTag: self.selectedIcon];
prevButton.highlighted = NO;
// Highlight tapped button:
self.selectedIcon = sender.tag;
[self performSelector:#selector(highlightButtonWithTag:) withObject:#(self.selectedIcon) afterDelay:0];
}
I have eight (8) UIButtons setup in my game. When one is selected it shows that it is selected and if you click it again it will show as unselected. However, I want to make it so that when you select a button and any of the other seven (7) are selected, they become unselected.
I know how to do this through the use of [buttonName setSelected:NO] but the problem is I can't pass buttonOne to buttonTwo if buttonTwo has already been passed to buttonOne because I have already imported buttonTwo's header file in buttonOne. It throws a parse error if I have both headers importing each other. I've been stuck on this for a while now and was hoping that someone might have a solution to my problem.
Thanks for any help.
Get the parent view of the current button and iterate through all the buttons inside, unselecting 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 on the comments, you could keep an array of buttons and go over it the same way the above code does with the subviews of the parent view. This will improve the performance of your code in case the view containing the buttons has many other subviews inside.
I know its too late to answer this question but I did it in only 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];
Simple way to do.
-(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];
}
I actually created an answer by reading all of your guys input, which I thank you greatly for. The tag property of the UIButton class was unknown to me before this post.
I created own subclass of UIButton, let's call it CustomUIButton.m. I created a NSMutableArray property for use when storing the buttons, which I'll call customButtonArray.
When I created the button, I set the tag property, and added the button to a local array on the parent view controller. After all buttons I wanted were created, I set the customButtonArray, like so:
// 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 (i.e. 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 a different buttons handleTap: is called, I iterated through the customButtonArray in the subclass main file and set the selected property to NO. I also set the correct image from another array property that I manually populated with the images, which I did so the array didn't have to be populated every time a button was pressed. At the end, unselected all other buttons, like so:
// 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];
}
}
}
Thanks for all of the useful information though, figured I should share the final answer I came up with in detail to help anyone else that comes across this problem.
I figured out a pretty easy way to solve this. My example is for 2 buttons but you can easily add more if statements for additional buttons. Connect all buttons to the .h file as properties and name them (I did button1 & button2). Place the following code in your .m file and Connect it (via the storyboard) to all of your buttons. Make sure when you are setting up your button to set an image for BOTH the normal UIControlStateNormal & UIControlStateSelected or this wont 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];
}
}
To answer "It throws a parse 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 whatever you're wanting to use as a forward class declaration:
#class MyCustomClass
#interface SomethingThatUsesMyCustomClass : UIViewController
#property (nonatomic, strong) MyCustomClass *mcc;
#end
Then #import the header in your .m file:
#import "MyCustomClass.h"
#implementation SomethingThatUsesMyCustomClass
-(MyCustomClass *)mcc
{
// whatever
}
#end
This approach will prevent errors caused by #import cycles.
Though I must say I agree with SergiusGee's comment on the question that this setup feels a bit strange.
The easiest approach here would be to get the parent UIView the buttons are on and iterate through it. Here's 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];
}
}
}
Did you try using ReactiveCocoa framework and add some blocks for your code , this is not the most simple approach yet i would say it is the most effective when you have multiple dependencies and very good for scaling
I have created a small project for a solution to your problem using my suggested approach (I tried to adapt it to the good old MVC pattern instead of my preferred MVVM)
you can find it here
https://github.com/MWaly/MWButtonExamples
make sure to install cocoa pods file as we need "ReactiveCocoa" and "BlocksKit" for this sample
we will use two main classes
ViewController => The viewController object displaying the buttons
MWCustomButton => Custom UIButton which handles events
when creating the buttons a weak reference to the viewController is also created using the property
#property (weak) ViewController *ownerViewController ;
events will be handled using the help of blocksKit bk_addEventHandler method and pass it to the block of the ViewController (selectedButtonCallBackBlock)
[button bk_addEventHandler:^(id sender)
{
self.selectedButtonCallBackBlock(button);
} forControlEvents:UIControlEventTouchUpInside];
now in the ViewController for each button touched the callBackButtonBlock will be trigerred , where it will change its 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 , it would listen for any changes in the property of "currentSelectedButton" of its ownerViewController and will change its selection property according to 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 would solve your problem , again your question might be solved in a simpler way , however i believe using this approach would be more scalable and cleaner.
Loop through all views in parent view. Check if it is a UIButton(or your custom button class) and not the sender. Set all views isSelected to false. Once loop is finished, set 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
}
Swift 4
//Deselect all tip buttons via IBOutlets
button1.isSelected = false
button2.isSelected = false
button3.isSelected = false
//Make the button that triggered the IBAction selected.
sender.isSelected = true
//Get the current title of the button that was pressed.
let buttonTitle = sender.currentTitle!
just wondering how to make a button "START" that when pressed triggers a function and the text changes to "STOP". then when pressed again the function will stop and the text changes back to "START"
Ive got the button already that starts the function. and i can handle changing the title, just not sure on what to use to make the 1 button have 2 functions
Add the IBAction method like:
- (IBAction)buttonTapped:(id)sender
{
UIButton *btn = (UIbutton *)sender;
NSString *title=btn.titleLabel.text;
if ([title isEqualToString:#"Start"])
{
//Start
}else
{
//Stop
}
}
Please try this:
- (IBAction) buttonAction:(id)sender
{
if([[(UIButton *)sender currentTitle]isEqualToString:#"START"])
{
[actionButton setTitle:#"STOP" forState:UIControlStateNormal];
//start the action here and change the button text to STOP
}
else if([[(UIButton *)sender currentTitle]isEqualToString:#"STOP"])
{
[actionButton setTitle:#"START" forState:UIControlStateNormal];
//stop the action here and change the button text to START
}
}
you have at least two options here:
Check for the title of your button and depending on the value call an action or the other.
Create two different buttons, each one with his action and show/hide them.