IBOutletCollection of UIButtons - changing selected state of buttons - objective-c

I'm having an issue with multiple UIButtons in a view. I'd like the buttons to be selected individually, with multiple selected at a time (example: 10 buttons, with buttons 1, 4, 5, 9 selected).
In my header I have a property for the IBOutletCollection:
#property (retain, nonatomic) IBOutletCollection(UIButton) NSMutableArray *buttonToStaySelected;
In my implementation, I have an IBAction:
-(IBAction)selectedButton:(id)sender{
for (UIButton *b in self.buttonToStaySelected) {
if (b.isSelected == 0){
[b setSelected:YES];
} else
[b setSelected:NO];
}
}
The issue I'm having is when I select any of the buttons tied to the collection, they all change to selected. I know the problem most likely (almost certain) lies in the loop, but every condition I've tried to stipulate breaks the code and leaves none of the buttons able to "change" state.
UPDATED
To have them selectable, change state and check off multiple, I used this as my final code:
-(IBAction)selectedButton:(id)sender {
for (UIButton *b in self.buttonToStaySelected) {
if (sender == b) {
[b setSelected:!b.isSelected];
}
}
}
Thanks for all the help!

The selectButton: message is sent with an argument which specifies the button that was tapped, but you apply the action to all buttons in the collection, not just the button that was tapped.
-(IBAction)selectedButton:(id)sender
{
for (UIButton *b in self.buttonToStaySelected)
{
if (sender == b)
{
b.isSelected == !b.isSelected
}
}
}

Related

How to detect change in UISegmentedControl from a separate IBAction

I have a UISegmentedControl button with three segments.
In ViewController.m this is working just fine -- pressing the buttons fires the correct methods.
I have another separate UIButton that when it is pressed it needs to first CHECK the state of the UISegmentedControl (to see which button is currently pressed) and then fire a method according to that segment value.
Here is my code for that separate UIButton. The button itself is working, but I cannot seem to figure out how to GET the current value of the segment of the UISegmentedControl.
Many thanks for any assistance here.
I am new to OBJ-C. I know how to do this in VisualBasic, so answers that are on the more verbose side would be most appreciated as I need to know the 'why'. Thank you.
- (IBAction)decodeButton:(id)sender {
UISegmentedControl *segment = [UISegmentedControl alloc]; // THIS DOES NOT WORK.
if (segment.selectedSegmentIndex == 0) {
decode(textToDecode);
} else if(segment.selectedSegmentIndex == 1) {
decode1(textToDecode);
} else if(segment.selectedSegmentIndex == 2) {
decode2(textToDecode);
}
}
Here is a Tutorial using UISegmentedControl in iOS.
Just Create a Reference object and wire it properly to File Owner.
IBOutlet UISegmentedControl *segmentedControl;
Then set property
#property (strong, nonatomic) IBOutlet UISegmentedControl * segmentedControl;
Synthesize in .m file
#synthesize segmentedControl;
Now You can Access the selected index at any time.
- (IBAction)decodeButton:(id)sender {
if (segmentedControl.selectedSegmentIndex == 0) {
decode(textToDecode);
} else if(segmentedControl.selectedSegmentIndex == 1) {
decode1(textToDecode);
} else if(segmentedControl.selectedSegmentIndex == 2) {
decode2(textToDecode);
}
}
Your code alloc every time UISegmentedControl in the button press action. So use the following code for sUISegmentedControl creation and its action .
SegmentChangeView=[[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:#"Segment1",#"Segment2",#"Segment3",nil]];
SegmentChangeView.frame=CGRectMake(5, 44, self.view.bounds.size.width-10, 33);
SegmentChangeView.selectedSegmentIndex=0;
SegmentChangeView.segmentedControlStyle=UISegmentedControlStyleBar;
SegmentChangeView.momentary = YES;
[SegmentChangeView setTintColor:[UIColor blackColor]];
NSDictionary *attributes =[NSDictionary dictionaryWithObjectsAndKeys:[UIFont fontWithName:#"Arial" size:13],UITextAttributeFont,nil];
[SegmentChangeView setTitleTextAttributes:attributes forState:UIControlStateNormal];
[SegmentChangeView addTarget:self action:#selector(SegmentChangeViewValueChanged:) forControlEvents:UIControlEventValueChanged];
SegmentChangeView.autoresizingMask=UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleBottomMargin;
[self.view addSubview:SegmentChangeView];
-(IBAction)SegmentChangeViewValueChanged:(UISegmentedControl *)SControl
{
if (SControl.selectedSegmentIndex==0)
{
decode(textToDecode);
}
else if (SControl.selectedSegmentIndex==1)
{
decode1(textToDecode);
}
else if (SControl.selectedSegmentIndex==2)
{
decode2(textToDecode);
}
}
You should remove UISegmentedControl *segment = [UISegmentedControl alloc] ; from your code, as it allocs anew instance of your UISegmentedControl every time, instead,
create an outlet for you UISegmentController like
#property (strong, nonatomic) IBOutlet UISegmentedControl * segment;
and then later at any point in your viewcontroller.m file, you can get the currently selected segment by using
segment.selectedSegmentIndex;
Hope this make sense,
Regards
Try like this
- (IBAction)segmentedControlChanged:(id)sender
{
UISegmentedControl *s = (UISegmentedControl *)sender;
if (s.selectedSegmentIndex == 1)
{
//code
}
else
{
//code
}
}
This code means you are creating a new Object on every click
UISegmentedControl *segment = [UISegmentedControl alloc] ;
The thing you have to do take IBOutlet (Property) of your segmentedControl then I will work for you. dont create a new object in the button method. when you will make a IBOutlet it will be link with at segmentControl and your code will work that time . Thanks

iOS: Using the same UIView for five buttons

I have a form with five different UIbutton instances. When I push one, I have to show different options, so my problem is, How can I know which button I have pushed using the same UIView? I don't want to create five UIViews. Is it possible give an ID to the buttons?
You can assign a tag to each UIButton in this manner :
[button setTag:4]
or you can set it in Interface Builder in the View attributes of the UIButton.
Then in your IBAction :
- (IBAction)message:(id)sender
{
int currentSender = [sender tag];
switch(currentSender) {
// Different actions
}
}
As #Florent pointed out, you can use a tag. But even this complication is not needed - you can directly compare the button objects themselves.
- (void)buttonClicked:(UIButton *)sender
{
if (sender == button1) {
// button 1 clicked
} else if (sender == button2) {
// etc.
}
}
Try this...
(IBAction)nextHipoacusia:(id)sender
{
int currentSender = ((UIButton *)sender).tag;
}

In Objective-c, detecting when all of a variable number of UIButton have been pressed

I have a quick question about the best method to check if all of my UIButtons have been pressed.
I have x number of UIButtons which I created programmatically.
Each button has its own unique tag (starting at 100 and incrementing upwards.)
When you click on a button is runs this:
- (void)myButtonAction:(id)sender
{
[self handleButton:sender];
}
- (void)handleButton:(UIButton *)button
{
// ???
}
If and only if the user has clicked on all buttons do a want an instance [self allButtonsClicked] to run.
What is the best way to do this? Should I make a NSMutableArray, and check to see if the tag number is in the NSMutableArray and if it is not, then add it.
And then when the NSMutableArray is equal in size to the x number of buttons then run [self allButtonsClicked].
What is the simplest method to make sure each and every button has been clicked?
*edit I figured it out after typing it out. Writing it out helped me get it.
-(void)letterreveal: (id)sender {
//data
UIButton *button = (UIButton *)sender;
//action
[self clickcheck:[NSNumber numberWithInt:button.tag]];
}
-(void)clickcheck:(NSNumber*)currenttag {
if ([self.buttonPressCounts containsObject:currenttag]) {
NSLog(#"case A");
}
else {
[self.buttonPressCounts addObject:currenttag];
NSLog(#"case B");
if([self.buttonPressCounts count]==[self.currentword length])
{
NSLog(#"fininshed");
}
}
}
buttonPressCounts is a NSMutablearray.
I just had to make sure to set it whenI made the buttons.
self.buttonPressCounts = [NSMutableArray arrayWithCapacity:[self.currentword length]];
currentword is a NSString (each button is a letter derived from the NSString).
You could create an NSMutableSet with all buttons and then remove each clicked button from that set until it is empty. Once the set is empty, you have certainly clicked all buttons.
If you dont mind, if a button was pressed once or more often, use a member ivar of NSMutableSet.
And I would use a number of the tag, but add /remove the button itself.

How to control UIButton on View without IB

I put some UIButtons on UIScrollView without IB.
If I click one button, other buttons are turned off except selected button.
But, When I click another button, other button ( except selected button) are turned off.
I can't confirm count of UIButtons on UIScrollView.
Because count of UIButtons are changed dynamically.
Without IB, How can I control UIButton on UIScrollView?
Plese tell me your advice. Thanks!
you can use:
NSUInteger count = 0;
for(id button in [scrollView subViews])
{
if([button isKindOfClass[UIButton class]])
{
count++;
}
}
NSLog("total buttons: %d",count);
You can tag the UIButtons when creating them [myButton setTag:MY_BUTTON_1] and later use this information when the button is tapped
-(IBAction)buttonPressed:(id)sender{
UIButton *button = (UIButton *)sender;
if ([button tag] == MY_BUTTON_1) { /* do something with this button */ }
else if ([button tag] == MY_BUTTON_2) { /* do something differently */ }
else return;
}

disable button when textfields are empty

hi im a beginner to programming and have been stuck on this task for ages and seem to be getting nowhere.
basically i have several textfields that generates the input information on a different page when the user presses a button. i would like the button to be disabled until all text fields are filled with information.
so far i have this:
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// make sure all fields are have something in them
if ((textfbookauthor.text.length > 0)&& (textfbookedition.text.length > 0)&& (textfbookplace.text.length > 0)&& (textfbookpublisher.text.length > 0) && (textfbookpublisher.text.length > 0) && (textfbooktitle.text.length > 0) && (textfbookyear.text.length > 0)) {
self.submitButton.enabled = YES;
}
else {
self.submitButton.enabled = NO;
}
}
the problem is the 'submitButton' is coming up with an error, what needs to go in its place?
i tried to put my button 'bookbutton'in it instead but its not working.
this is my function for the 'generate' button
-(IBAction)bookbutton:(id)sender;
{
NSString* combinedString = [NSString stringWithFormat:
#"%# %# %#.%#.%#:%#.",
textfbookauthor.text,
textfbookyear.text,
textfbooktitle.text,
textfbookedition.text,
textfbookplace.text,
textfbookpublisher.text];
BookGenerate*bookg = [[BookGenerate alloc] init];
bookg.message = combinedString;
bookg.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:bookg animated:YES];
[BookGenerate release];
}
if anybody knows how i can make it work or what i need to add please help.
thanks in advance
Make an Outlet for every UITextField and create an IBAction in your .h:
IBOutlet UITextField *textField1;
IBOutlet UITextField *textField2;
IBOutlet UITextField *textField3;
IBOutlet UIButton *button
- (IBAction)editingChanged;
Connect all the outlets and connect the IBAction to every textfield with editingChanged:
- (IBAction)editingChanged {
if ([textfield1.text length] != 0 && [textfield2.text length] != 0 && [textfield3.text length] != 0) {
[button setEnabled:YES];
}
else {
[button setEnabled:NO];
}
}
Note that you can also use [textfield.text isEqualToString:#""] and put a ! in front of it (!means 'not') to recognize the empty textField, and say 'if the textField is empty do...'
And:
- (void)viewDidLoad {
[super viewDidLoad];
[button setEnabled:NO];
}
If you have a button and you want to enable it only if there is a text in a textfield or textview, implement the follow method
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if (textView.text.length > 1 || (text.length > 0 && ![text isEqualToString:#""]))
{
self.button.enabled = YES;
}
else
{
self.button.enabled = NO;
}
return YES;
}
Few solutions are available on these posts as well
Very Similar Query
A different version of it
Key here is using (extending) UITextFieldDelegate class and it's associated function
//Need to have the ViewController extend UITextFieldDelegate for using this feature
func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool {
// Find out what the text field will be after adding the current edit
let text = (textField.text as NSString).stringByReplacingCharactersInRange(range, withString: string)
if !text.isEmpty{//Checking if the input field is not empty
button.userInteractionEnabled = true //Enabling the button
} else {
button.userInteractionEnabled = false //Disabling the button
}
// Return true so the text field will be changed
return true
}
You should use" textfield should change chracters in range" (see apple docs for uitextviewdelegate). because it updates as users type information." Textfield did end editing" only fires when the users finishes editing a textfield or hits enter. In most cases, someone will fill in the last field and leave the cursor sitting there and expect the button to become enabled...but that wont happen using "textfield did end editing" just because they entered input.
You can also do this to check the length
if([self.textfiele.text isEqualToString:#""])
In addition to having IBOutlets for each UITextField, it might be helpful to have an IBOutletCollection declared that contains all 3 text fields in an array.
#property (nonatomic, retain) IBOutletCollection(UITextField) NSArray *textFields;
Then in your implementation just #synthesize textFields and you can quickly loop the text fields it contains, checking for text.
- (IBAction)editingChanged
{
BOOL buttonShouldBeEnabled = YES;
for (UITextField *field in self.textFields)
if (!field.text.length)
buttonShouldBeEnabled = NO;
button.enabled = buttonShouldBeEnabled;
}