Can't read the segmentedcontroll index - iphone

I have implemented several of UISegmentedControl objects before but for one or other reason I am unable to implement it within a tableview cell. I want the user to choose his gender. if the value of the segmentedControl changed a method gets called to save it for further processing.
self.seg = [[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:#"Man",#"Female", nil]];
[self.seg addTarget:self action:#selector(toggleGender) forControlEvents:UIControlEventValueChanged];
I created the method:
-(void)toggleGender{
NSLog(#"%d",self.seg.selectedSegmentIndex)
if (self.seg.selectedSegmentIndex == 0)
{
NSLog(#"User is a man");
} else if (self.seg.selectedSegmentIndex == 1)
{ NSLog(#"User is a female");
}
}
The first NSLog prints -1 as value if the value has changed.
I declared seg in the header file, and created a property and synthesized it!
I am currently NOT dealllocing this object. (I know this is a memory leak)
Why am I unable to read-out the selected segment, and why does it give back -1 as selected item?

Try this :
self.seg = [[UISegmentedControl alloc]initWithItems:[NSArray arrayWithObjects:#"Man",#"Female", nil]];
[self.seg addTarget:self action:#selector(toggleGender:) forControlEvents:UIControlEventValueChanged];
(NOTE THE ':' in the #selector..). And change your function by this :
-(void)toggleGender:(id)sender
{
if ([sender isKindOfClass:[UISegmentedControl class]])
{
NSLog(#"%d",[(UISegmentedControl *)sender selectedSegmentIndex]);
if ([(UISegmentedControl *)sender selectedSegmentIndex] == 0)
{
NSLog(#"User is a man");
}
else if ([(UISegmentedControl *)sender selectedSegmentIndex] == 1)
{
NSLog(#"User is a female");
}
}
}

Related

Check if any textfield, textview or label changed for a UIViewController..?

I have a view controller and it contains n number of UITextFields and UItextViews and UILabels, is there anyhow I can get notified if any of them changes..?
I can do it by manually looking at each of them in their respective TextDidChangeNotification and similar but I am looking for a more optimized way of doing this, where I don't have to worry about each of them .
// Assumes you don't use tag values now - if you do small change to create
// and index set, add the ones you use, so all new ones assigned are unique.
// assumes ARC
1) New ivar:
{
NSMutableDictionary *savedValues;
}
1) When you want to baseline the values:
savedValues = [self snapshot];
2) call this to baseline current values initially then at any later point:
- (NSMutableDictionary *)snapshot
{
NSInteger tag = 1;
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:[self.view.subviews count]];
for(UIView *v in self.view.subviews) {
if([v isKindOfClass:[UILabel class]] || [v isKindOfClass:[UITextField class]] || [v isKindOfClass:[UITextView class]]) {
if(v.tag == 0) v.tag = tag++; // will happen once
// EDIT below
    [dict setObject:[NSString stringWithString:[(id)v text]] forKey:[NSNumber numberWithInteger:tag]];
}
}
return dict;
}
4) When you want to see if anything changed:
- (BOOL)anyChanges
{
NSDictionary *currentDict = [self snapshot];
return [currentDict isEqualToDictionary:savedValues];
}
You should use one method for all textFields, textView and Labels. and give a unique tag to textFields and textViews and labels. which help you for define it's textField ,textView or Label.
if(sender.tag == 1000)//UILabel
{
UILabel *label=(UILabel *)sender
//write own code for label what do you want.
}
else if(sender.tag == 2000)//UITextField
{
UITextField *textField=(UITextField *)sender
//write own code for textField what do you want.
}
else if(sender.tag == 3000)// UITextView
{
UITextView *textView=(UITextView *)sender
//write own code for textView what do you want.
}
Make your class to handle UIControlEventValueChanged event in your textfield, textview or label's value is changed. Add this line ViewDidLoad method:
[youLabel addTarget:self action:#selector(valueChanged:)
forControlEvents:UIControlEventValueChanged];
// add for textfield, textview also if needed
[youTextField addTarget:self action:#selector(valueChanged:)
forControlEvents:UIControlEventValueChanged];
[youTextView addTarget:self action:#selector(valueChanged:)
forControlEvents:UIControlEventValueChanged];
Now selector would be called when ever value is changed
- (void) valueChanged:(id)sender{
if(sender isKindofClass[UILabel class])
{
//label value changed here to differntiate used tag
if([sender tag] == 0)
....
....
}
else if(sender isKindofClass[UITextField class])
{
// textField value changed to differntiate used tag
if([sender tag] == 0)
....
....
}
else if(sender isKindofClass[UITextView class])
{
// textview value changed to differntiate used tag
if([sender tag] == 0)
....
....
}
}

How to handle events of multiple segmented control in a single view

I have 2 segmented controls in my viewcontroller view. How can I handle the tap events of both of the segmented controllers?
There are two ways to do so.
Add different actions for every segment control
Add same actions for every segment control & check which control is tapped using its tag.
[yourSegmentedControl addTarget:self action:#selector(segmentSwitch:) forControlEvents:UIControlEventValueChanged];
- (IBAction)segmentSwitch:(id)sender
{
UISegmentedControl *segmentedControl = (UISegmentedControl *) sender;
if(segmentedControl.tag == someTag)
{
if(segmentedControl.selectedSegmentIndex == 1)
{
// your code
}
else if(segmentedControl.selectedSegmentIndex == 2)
{
// your code
}
}
else if(segmentedControl.tag == someTag)
{
if(segmentedControl.selectedSegmentIndex == 1)
{
// your code
}
else if(segmentedControl.selectedSegmentIndex == 2)
{
// your code
}
}
}
Apple docs says:
http://developer.apple.com/library/IOs/#documentation/UIKit/Reference/UISegmentedControl_Class/Reference/UISegmentedControl.html
You register the target-action methods for a segmented control using the UIControlEventValueChanged constant as shown below.
[segmentedControl addTarget:self
action:#selector(action:)
forControlEvents:UIControlEventValueChanged];
So, you just have to register action for every segmented control.
Set the tag property on each segmented control to a different integer. Then in your method you set as the action for when the value changes, check which integer the tag property is set to using [sender tag].
You can use selected mode of segment:
UISegmentedControl *tempSegment = sender;
if ([tempSegment selectedSegmentIndex] == 0){
//first Action
}
else if ([tempSegment selectedSegmentIndex] == 1){
//second Action
}
Assign two different actions to these segmented controls:
[segmentedControl addTarget:self
action:#selector(action:)
forControlEvents:UIControlEventValueChanged];
Swift version:
#IBAction func yourFunctionName(sender: UISegmentedControl) {
if (sender.selectedSegmentIndex == 0){//choice 1
}else{//choice 2
}
}

how to use if else conditon on button press based on image of button?

I am trying to use some logics on the base of button click.i use button as checkmark and when i click on this check mark the image of button changed into checked.png or unchecked.png.On that basis i use this code...
if([UIImage imageNamed:#"checkbox_ticked.png"])
{
isActiveStr=[arrayPickerData objectAtIndex:17];
NSLog(#" is active value is %# ",isActiveStr);
isActiveStr=nil;
}
else
{
NSLog(#"no vlaue send");
isActiveStr=[[NSMutableString alloc]initWithString:#"1"];
NSLog(#" is active value %#",isActiveStr);
}
Now i dont know how to use the else condtion...i run this code but it always run only if codition.It never goes in else conditon.I want that i codtion is true it goes in if part and when condition is false it goes in else part.And how i use image property of button to check the condition.
You have to have a flag variable that holds the status of the button(checked/unchecked).
BOOL checked;
And, you have to update it when ever you click on the the button.
- (void)onButtonTapped:(UIButton *)button {
checked = !checked;
...
}
And change your if statement like this,
if (checked) {
// The button is checked
} else {
// The button is not checked
}
Try this if statement:
if ([[myButton imageForState:UIControlStateNormal] isEqual:[UIImage imageNamed:#"checkbox_ticked.png"]]) {
...
But as for me this is bad approach, better to have some bool flag that indicate that button is checked.
the if condition will always evaluate true. You should instead check for [myButton state] to see if it's enabled or not. You may have to add an IBOutlet or IBAction according to your needs.
USE this in your IBAction method
if(!btnCheckbox.selected)
{
[btnCheckbox setImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"check-out_h" ofType:#"png"]] forState:UIControlStateNormal];
btnCheckbox.selected=YES;
}
else {
[btnCheckbox setImage:[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"check-out" ofType:#"png"]] forState:UIControlStateNormal];
btnCheckbox.selected=NO;
}
-(void)checkBoxIsHideNationWideClicked
{
NSLog(#"nation wide button clicked");
mybtn.selected=!mybtn.selected;
defaultsCheckBox=[NSUserDefaults standardUserDefaults];
if (mybtn.selected)
{
[defaultsCheckBox setValue:#"One" forKey:#"CheckBox"];
NSLog(#" is active value is %# is fetched succesfuly",hideNationWideStr);
[CommonVar setHideNationwideData:hideNationWideStr];
NSLog(#" is active value send to cmmon class %# sent succesfuly",hideNationWideStr);
}
else
{
[defaultsCheckBox setValue:#"Two" forKey:#"CheckBox"];
NSLog(#"no vlaue send");
hideNationWideStr=[[NSMutableString alloc]initWithString:#"1"];
[CommonVar setHideNationwideData:hideNationWideStr];
NSLog(#" is active value send to cmmon class %# sent succesfuly",hideNationWideStr);
}
}

Hiding or moving SegmentContoller

Hello I've tried for 3 weeks to solve this issue and it stumps me. What i am trying to do is create a 3 part segment from an array, display it in a view in a certain position, then remove it from view when the "OFF" flag is set. Every thing works except the removal of the segment. It will even commuticate with (pickOne) and display the segment letters in a label. What i can't get to work is either of the two: setHidden:YES, or removeAllSegments. Any help would be appreciated. Here is my code.
- (void) showSegment {
int x = 192;
int y = 212;
int w = 125;
int h = 25;
SegUnit1 = #"A";
SegUnit2 = #"B";
SegUnit3 = #"C";
threeSegs = [NSArray arrayWithObjects: SegUnit1, SegUnit2, SegUnit3, nil];
segSize = [NSArray arrayWithArray:threeSegs];
UISegmentedControl *heightSC = [[UISegmentedControl alloc] initWithItems:segSize];
if ([segmentState_height isEqualToString:#"ON"]) {
NSLog(#"segmentState_height = %#",segmentState_height);
heightSC.frame = CGRectMake(x, y, w, h);
heightSC.segmentedControlStyle = UISegmentedControlStyleBar;
heightSC.selectedSegmentIndex = -1;
[heightSC addTarget:self
action:#selector(pickOne:)
forControlEvents:UIControlEventValueChanged];
[self.view addSubview:heightSC];
[heightSC release];
} else if ([segmentState_height isEqualToString:#"OFF"]) {
NSLog(#"segmentState_height = %#",segmentState_height);
[heightSC setHidden:YES]; // NSLog showing "OFF" but segment will not hide.
[heightSC removeAllSegments]; // NSLog showing "OFF" and segment is suppose to dismantle and does not.
}
}
I know now that i have to "not" create and remove in the same function, and was given a tip on correcting this but I don't know how to use the tip.
here is what was suggested.
Well, your method is a little confused, since you are trying to both create and hide at the same time. So you might consider splitting that up into separate methods.
In general, it will be along these lines:
Code:
if ([self theControlProperty] == nil)
{
UISeg... *theControl = [[UISeg alloc] ....];
[self setTheControlProperty:theControl];
...
}
if (shouldHideTheControl)
{
[[self theControlProperty] setHidden:YES];
}
Any help would be appreciated.
The problem you have is that you're creating a new UISegmentedControl instance every time that method is called. The first time through, you create an instance and add it as a subview to your view. This apparently works fine, as it should. Then the method returns, and you no longer have any easy way to refer to that instance that you created. When you re-enter -showSegment, you create a different instance, and then hide and/or destroy it. This different instance has no effect whatsoever on the instance that you gave to the view.
What you need to do is make heightSC an instance variable. Add it to the interface declaration in the header file, then initialize it only once, and hide or modify it as needed subsequently. The key point is that you need to have a reference to the instance of the UISegmentedControl which is being drawn on the screen, a reference that lives outside the method itself that you can use the second, third, fourth, etc time you call that method.
Try using the remove segments in your button choice method pickOne. This takes it outside the showSegment method and matches the users desired action to make the change and clear off the buttons.
- (void) pickOne:(id)sender {
UISegmentedControl* userChose = sender;
if( [userChose selectedSegmentIndex] == 0 ){
your first button operation;
[heightSC removeAllSegments];
}
if( [userChose selectedSegmentIndex] == 1 ){
your second button operation;
[heightSC removeAllSegments];
}
if( [userChose selectedSegmentIndex] == 2 ){
your third button operation;
[heightSC removeAllSegments];
}
}
I tried this and got the results I was looking for. Thanks goes to Mythogen and BrianSlick I just need to check and make sure there are no leaks. Now that will be a task.
Does anyone know if I need the second [heightSC release]; ?
// .h
# interface ------ {
UISegmentedControl *segmentPicked;
}
|
#property (nonatomic, retain) UISegmentedControl *segmentPicked;
// .m
|
#synthesize segmentPicked;
|
if ([self segmentPicked] == nil) {
UISegmentedControl *heightSC = [[UISegmentedControl alloc] initWithItems:segSize];
[self setSegmentPicked:heightSC];
[heightSC release];
heightSC.frame = CGRectMake(x, y, w, h);
heightSC.segmentedControlStyle = UISegmentedControlStyleBar;
heightSC.selectedSegmentIndex = -1;
[heightSC addTarget:self
action:#selector(pickOne:)
forControlEvents:UIControlEventValueChanged];
[self.view addSubview:heightSC];
[heightSC release];
}
if ([segmentState_height isEqualToString:#"OFF"])
{
[[self segmentPicked] setHidden:YES];
} else {
[[self segmentPicked] setHidden:NO];
}
[yourSegment removeFromSuperview];
?

how to find which objects are selected:TRUE from 64 buttons labelled b1, b2 etc

I have a project where there are 64 buttons, you have to click certain ones, then click 'done'. If you clicked the right ones, you get some points, and those then need to disappear.
I have let the user keep track of which buttons are pressed by doing sender setSelected:TRUE.
The first bit is all working fine, but I'd like to be able to then hide the buttons that were selected when the user clicked 'done'.
My current thoughts are:
- what I used in Actionscript to do the same thing was
for (i=1;i++;i<65) {
if(getProperty ("b"+ i, _visible) == true) {do blah blah blah} }
I'm really really really hoping there is an obvious equivalent in objective C that does the same thing?
I definitely do not want to have to go through all 64 buttons and type if ([b1 isSelected == TRUE]etc...
I can't just use sender, as it may be several buttons that have previously been selected that I need to access.
EDIT -
This is now the code that is called when user presses one of the 64 buttons.
-(IBAction) pressed:(id)sender {
UIButton *button = (UIButton *)sender;
if ([sender isSelected] ==FALSE) {
[sender setSelected:TRUE];
}
else {
[sender setSelected:FALSE];
}
if ([myArray containsObject:sender])
{
[myArray removeObject:sender];
}
else {
[myArray addObject:sender];
}
}
This is called when they press the 'done' button.
-(IBAction) checkTotal:(id)sender {
if (total == [(totaltxt.text) intValue]) {
score += 1;
scoretxt.text = [NSString stringWithFormat:#"%i", score];
for (UIButton *b in myArray)
{
[b setHidden:TRUE];
}
[myArray removeAllObjects];
}
else {
// some indication that they pressed the button but were wrong.
}
}
It unfortunately still won't hide the button.
It works if I change it to [n1 setHidden:TRUE] to hide the matching textbox above the button, but won't hide even a specific button -eg- [b1 setHidden:TRUE], let alone all the buttons in my array.
AAAAAAAARGH!!!!
Any ideas?
You can iterate on your view's subviews, and check whether the subview is a button:
for (UIView *view in self.view.subviews)
{
if ([view isKindOfClass: [UIButton class]])
{
// Do processing here
// For instance:
if ((UIButton *)view).isSelected)
view.hidden = YES;
}
}
If you dont want to iterate through all the buttons then how about store a reference to your button in an array then just iterate through that array and clear it when the use clicks done?
-(void)click:(id)sender
{
if([myArray containsObject:sender])
[myArray removeObject:sender];
else
[myArray addObject:sender];
}
-(void)doneClicked:(id)sender
{
for(UIButton *b in myArray)
{
[b setHidden:TRUE];
}
[myArray removeAllObjects]; //whateverr the method is i dont remember it off the top of my head
}
Try [b setAlpha:0.0];
Set the tag when creating the buttons and store the tag index in an array.
-(IBAction) pressed:(id)sender {
}
by sender.tag
then finally run the loop hide all object
and again run loop to unhide the object if it exists in array.