How do i toggle UIButton using currentTitle in XCode - iphone

To the point, i have 10 button and i write a number in Title inside every button, that is 0 to 9. My problem in here is, how do i toggle a button function, just say when i press a number 0, the value will show in showLabel.text is 0 and the button is in selected state but when i push it again, the number is gone in showLabel.text and the button is change back to normal state. I using this below code but it can't solve my problem. I mean, just say i selected number "1, 5, 7, 8" and i want to deselect number 5, using below code my showLabel will replace all number to none not to be "1, 7, 8". So i think this is not good idea using this code.
-(IBAction)numberBtn:(UIButton *)sender
{
UIButton *button = (UIButton *)sender;
[button setTitle:#"X" forState:UIControlStateSelected];
button.selected = !button.selected;
if (button.selected)
{
number = sender.currentTitle;
showLabel.text = [showLabel.text stringByAppendingFormat:number];
}
else
{
showLabel.text = [NSString stringWithFormat:#""];
}
}
Is there anyway to do that? Happy holiday.

Well. A think it will be good idea to make an array of 10 Boolean values and every time your button has been pressed - you just need to toggle corresponded value in your Boolean array and update your label using "for" loop:
for (int nn=0; nn<10; ++nn) if (boolVals[nn]) [myString appendFormat #"%d ", nn];

Do this instead:
- (IBAction)numberBtn:(UIButton *)sender {
sender.selected = !sender.selected;
if (sender.selected)
{
NSString *number = sender.currentTitle;
showLabel.text = [showLabel.text stringByAppendingString:number];
}
else
{
NSString *newString;
NSString *number = sender.currentTitle;
NSString *string = showLabel.text;
for (int i = 0; i<string.length; ++i) {
NSString *sub = [string substringWithRange:(NSRange){i, 1}];
if ([sub isEqualToString:number]) {
newString = [string substringToIndex:i];
newString = [newString stringByAppendingString:[string substringFromIndex:i+1]];
}
}
showLabel.text = newString;
}
[sender setTitle:#"X" forState:UIControlStateSelected];
}

Related

Adding a method to my uitextfield in cell?

I am adding this Method to my code to format the textfield. I am using the code below to try and add the method, but it not working, what am I doing wrong?
.h file
NSString* phone_;
UITextField* phoneFieldTextField;
#property (nonatomic,copy) NSString* phone;
.m file
#synthesize phone = phone_;
ViewDidLoad{
self.phone = #"";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
// Make cell unselectable and set font.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont fontWithName:#"ArialMT" size:13];
if (indexPath.section == 0) {
UITextField* tf = nil;
switch ( indexPath.row ) {
case 3: {
cell.textLabel.text = #"Phone" ;
tf = phoneFieldTextField = [self makeTextField:self.phone placeholder:#"xxx-xxx-xxxx"];
phoneFieldTextField.keyboardType = UIKeyboardTypePhonePad;
[self formatPhoneNumber:phoneFieldTextField.text deleteLastChar:YES];
[cell addSubview:phoneFieldTextField];
break ;
}
// Textfield dimensions
tf.frame = CGRectMake(120, 12, 170, 30);
// Workaround to dismiss keyboard when Done/Return is tapped
[tf addTarget:self action:#selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];
}
}
// Textfield value changed, store the new value.
- (void)textFieldDidEndEditing:(UITextField *)textField {
//Section 1.
if ( textField == nameFieldTextField ) {
self.name = textField.text ;
} else if ( textField == addressFieldTextField ) {
self.address = textField.text ;
} else if ( textField == emailFieldTextField ) {
self.email = textField.text ;
} else if ( textField == phoneFieldTextField ) {
self.phone = textField.text ;
}else if ( textField == dateOfBirthTextField ) {
self.dateOfBirth = textField.text ;
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString* totalString = [NSString stringWithFormat:#"%#%#",textField.text,string];
// if it's the phone number textfield format it.
if(textField.tag == 10 ) {
if (range.length == 1) {
// Delete button was hit.. so tell the method to delete the last char.
textField.text = [self formatPhoneNumber:totalString deleteLastChar:YES];
} else {
textField.text = [self formatPhoneNumber:totalString deleteLastChar:NO ];
}
return false;
}
return YES;
NSLog(#"Testing should change character in range");
}
-(NSString*) formatPhoneNumber:(NSString*) simpleNumber deleteLastChar:(BOOL)deleteLastChar {
if(simpleNumber.length == 0) return #"";
// use regex to remove non-digits(including spaces) so we are left with just the numbers
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[\\s-\\(\\)]" options:NSRegularExpressionCaseInsensitive error:&error];
simpleNumber = [regex stringByReplacingMatchesInString:simpleNumber options:0 range:NSMakeRange(0, [simpleNumber length]) withTemplate:#""];
// check if the number is to long
if(simpleNumber.length>10) {
// remove last extra chars.
simpleNumber = [simpleNumber substringToIndex:10];
}
if(deleteLastChar) {
// should we delete the last digit?
simpleNumber = [simpleNumber substringToIndex:[simpleNumber length] - 1];
}
// 123 456 7890
// format the number.. if it's less then 7 digits.. then use this regex.
if(simpleNumber.length<7)
simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:#"(\\d{3})(\\d+)"
withString:#"($1) $2"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [simpleNumber length])];
else // else do this one..
simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:#"(\\d{3})(\\d{3})(\\d+)"
withString:#"($1) $2-$3"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [simpleNumber length])];
if (simpleNumber.length == 10 && deleteLastChar == NO) { [self resignFirstResponder];}
return simpleNumber;
NSLog(#"Testing format phone number");
}
#pragma mark - TextField
-(UITextField*) makeTextField: (NSString*)text
placeholder: (NSString*)placeholder {
UITextField *tf = [[UITextField alloc] init];
tf.placeholder = placeholder;
tf.text = text ;
tf.autocorrectionType = UITextAutocorrectionTypeNo ;
tf.autocapitalizationType = UITextAutocapitalizationTypeNone;
tf.adjustsFontSizeToFitWidth = YES;
tf.returnKeyType = UIReturnKeyDone;
tf.textColor = [UIColor colorWithRed:56.0f/255.0f green:84.0f/255.0f blue:135.0f/255.0f alpha:1.0f];
return tf ;
}
The method you are using:
-(NSString*) formatPhoneNumber:(NSString*) simpleNumber deleteLastChar:(BOOL)deleteLastChar
Returns an NSString Object. In your case you are calling the method correctly but you are not setting the Returned NSString object to anything. It is simply hanging there. You need to set the phoneFieldTextField to the formatted text like so:
phoneFieldTextField.text = [self formatPhoneNumber:phoneFieldTextField.text deleteLastChar:YES];
NOTE - If you want to learn more about return methods then read the following:
If you noticed some most methods are of the void type. You know this when you see a method like this:
- (void)someMethod {
int x = 10;
}
What void means is that the someMethod does not return anything to you. It simply executes the code within the method. Now methods than return an object or some other data type look like this:
- (int)returnSomething {
int x = 10;
return x;
}
First thing you will notice is the return type is no longer void, it is an int. This means the method will return an integer type. In this case the code executes and you are returned the value of x.
This is just the start of the topic of return methods but hopefully it makes things a bit clearer for you.
First off you need to tell us What is not working we don't have your app and all your code. You need to explain what is working and what is not working exactly. It took longer then necessary to figure out that your question is why is textField:shouldChangeCharactersInRange: not working. Did you set a breakpoint in the function to see what it was doing. Was it not being called?
That said your bug is that textField:shouldChangeCharactersInRange: is using tags to identify text fields but the rest of the code is using pointers
// if it's the phone number textfield format it.
- if(textField.tag == 10 ) {
+ if(textField.tag == phoneFieldTextField ) {
Also you didn't include the code for makeTextField:placeholder: There could be issues in it too. Compare your code to the makeTextField:placeholder: in my sample.
I created a sample project on GitHub. To fix this. I also demos a better approach to creating input forms using table views.
https://github.com/GayleDDS/TestTableViewTextField.git
Look at both diffs to see what I did to YourTableViewController.m to make things work.
https://github.com/GayleDDS/TestTableViewTextField/commit/d65a288cb4da7e1e5b05790ea23d72d472564793
https://github.com/GayleDDS/TestTableViewTextField/commit/31ecaec8c9c01204643d72d6c3ca5a4c58982099
There is a bunch of other Issues here:
You need to call [super viewDidLoad]; in your viewDidLoad method
You need to correctly indent your code (could be a cut and paste issue)
You should be using the storyboard to create your views. See the better solution tab and BetterTableViewController implementation.
Must Watch - iOS Development Videos
WWDC 2011 - Session 309 - Introducing Interface Builder Storyboarding
https://developer.apple.com/videos/wwdc/2011/?id=309
Stanford iPhone Programing Class (Winter 2013)
Coding Together: Developing Apps for iPhone and iPad
https://itunes.apple.com/us/course/coding-together-developing/id593208016
Lecture 9. Scroll View and Table View
Lecture 16. Segues and Text Fields
Looks like you are not setting the delegate <UITextFieldDelegate> in the .h file, and not assigning your textfield's delegate property to self tf.delegate = self; in order to call - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Try that and let me know how it goes
-Good Luck!
#koray was right: you need to setup the delegate for the class. Your class should be declared as implementing the protocol UITextFieldDelegate (in addition to UITableViewDataSource, I assume)
then in your makeTextField: (NSString*)text placeholder: (NSString*)placeholder method, you need to have something like:
-(UITextField*) makeTextField: (NSString*)text
placeholder: (NSString*)placeholder {
UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(40, 0, 150, 40)];
tf.placeholder = placeholder;
// (...)
tf.delegate = self;
return tf ;
}
Then you need to setup the delegate methods correctly. In the following example, I have a nav bar, since the numbers pad doesn't have a return or a done button. I setup a button that will act as the done button (you may have another way of making the keyboard go, and switching between text fields will trigger the end of edition anyway):
- (void) textFieldDidBeginEditing:(UITextField *)textField {
UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneEditing:)];
self.navBar.topItem.rightBarButtonItem = doneBtn;
}
- (void) doneEditing:(id) sender {
if(phoneFieldTextField.isFirstResponder) {
[phoneFieldTextField resignFirstResponder];
}
// (...)
self.navBar.topItem.rightBarButtonItem = nil;
}
Then, the magic happens in the textDidEndEditing delegate method:
- (void)textFieldDidEndEditing:(UITextField *)textField {
if ( textField == phoneFieldTextField ) {
self.phone = [self formatPhoneNumber:textField.text deleteLastChar:YES] ; // convert
[phoneFieldTextField setText:self.phone]; // display
}
// (...)
}

Changing button label not working properly with if-else method

it is probably a very simple problem but I spent already a lot of time on it and just have given up...
I have a button and a textfield for speed calculations. I want the button label change once the button is pressed (km/h >> mph >> m/s >> km/h and so on) and speed recalculated. It sometimes works fine but very often it jumps to "else" statement even if the CurrentSpeedValue is #"km/h". Could anyone help? Maybe it would be better to use switch-case method but how should it be stated?
- (IBAction)speedChange:(id)sender {
//CurrentSpeedUnit is saved to NSUserDefault in another action
if (CurrentSpeedUnit == #"km/h") {
[sender setTitle:#"mph" forState:UIControlStateNormal];
CurrentSpeedUnit = #"mph";
float speedToPrint = ([textSpeed.text floatValue]) / 1.609344;
textSpeed.text = [[NSString alloc] initWithFormat:#"%.3f", speedToPrint];
} else if (CurrentSpeedUnit == #"mph") {
[sender setTitle:#"m/s" forState:UIControlStateNormal];
CurrentSpeedUnit = #"m/s";
float speedToPrint = ([textSpeed.text floatValue]) * 1.609344 / 3.6;
textSpeed.text = [[NSString alloc] initWithFormat:#"%.3f", speedToPrint];
} else {
[sender setTitle:#"km/h" forState:UIControlStateNormal];
CurrentSpeedUnit = #"km/h";
float speedToPrint = ([textSpeed.text floatValue]) * 3.6;
textSpeed.text = [[NSString alloc] initWithFormat:#"%.3f", speedToPrint];
}
}
For string comparison you need to use
isEqualToString
For Example:
if ([CurrentSpeedUnit isEqualToString:#"km/h"])
{
// Perfrom Action
}...
You should not compare strings like that (you compare pointers but not the contents). Use isEqualToString.
i.e.
if ([CurrentSpeedUnit isEqualToString:#"km/h"]) {
...
but not your
if (CurrentSpeedUnit == #"km/h") {
It may work sometimes, but just remember to avoid comparing strings with ==

How can I force the keyboard to stay displayed?

I have an IBAction that is called when someone is done entering text in a field. I then validate the input. If I have determined there is an error, I display a message and want the user to enter into that same field again. Rather than make them select the text field to bring the keyboard up (which works fine) I want to just leave the keyboard displayed.
I am doing [SymbolEntered becomeFirstResponder]; as the last statement in my IBAction, but the keyboard still goes away. Am I putting that in the wrong place? Any help would be appreciated. Thanks.
- (IBAction)textFieldDoneEditing:(id)sender {
DebugMsg.text = nil;
DebugMsg2.text = nil;
DebugMsg3.text = nil;
NSLog (#"done editing");
NSLog (#"%#", SymbolEntered.text);
if ([SymbolEntered.text isEqualToString:nil])
{
Result.textColor = [UIColor redColor];
Result.text = #"You must enter a symbol!";
[SymbolEntered becomeFirstResponder];
}
else
{
if ([SymbolEntered.text isEqualToString:
[NSString stringWithCString:elements_table2[el_tbl_idx-1].element_symbol]])
{
correct_count++;
Result.textColor = [UIColor greenColor];
Result.text = #"Correct!";
Score.hidden = FALSE;
Score.text = [NSString stringWithFormat:#"Score: %d out of %d - %d Percent", correct_count, el_count+1,
(correct_count*100)/(el_count+1)];
GetNextElementButton.hidden = FALSE;
SymbolEntered.enabled = FALSE;
el_count++;
attempts = max_tries + 1;
}
else
{
Score.hidden = TRUE;
Result.textColor = [UIColor redColor];
if (attempts < max_tries)
{
if (attempts+1 == max_tries)
{
Result.text = #"Sorry, one more try -";
}
else
{
Result.text = #"Sorry, try again - ";
}
GetNextElementButton.hidden = TRUE;
attempts++;
}
else
{
Result.text = [[NSString alloc] initWithFormat: #"Sorry. The correct answer is %#",
[NSString stringWithCString:elements_table2[el_tbl_idx-1].element_symbol]];
Score.hidden = FALSE;
Score.text = [NSString stringWithFormat:#"Score: %d out of %d - %d Percent", correct_count, el_count+1, (correct_count*100)/(el_count+1)];
GetNextElementButton.hidden = FALSE;
SymbolEntered.enabled = FALSE;
el_count++;
}
}
}
[SymbolEntered becomeFirstResponder];
NSLog (#"end of textfieldoneediting");
}
You can do your validation in the UITextField textFieldShouldEndEditing: delegate method instead. If you return NO from that callback, the text field will remain first responder and the keyboard won't go away. (You'll have to make your controller object the text field's delegate if it isn't already, of course.)
Try calling the [textField becomeFirstResponder] sometime later? Also make sure the UITextField pointer is not nil or something. For more help please show some of your code, it's very hard to tell where the problem is like this.
-(BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
Try This it will resign the keyboard.

Dynamically Add Textfield with tag On button Part-2

I want to add a textfield dynamically with tag so that it can give unique value every time. And than add those values and show on label. When I click button one textfield add "n" give the value, and that value adds to the previous value.
Value adding Successfully. But when I edit anything, change or give another value such as (10 instead of 12) the loop will run again because of this line
[Txt_New_Estimated addTarget:self action:#selector(C6Loop) forControlEvents:UIControlEventEditingDidEnd];
2nd problem is that when I add a new textfield then the previous textfield did not modify and do not add in rest of textfields... before adding a new textfield it works properly but when edit anything loop will run again.... i want to overCome this problem, so please check this code and give some possible solution. I am sending my code here Please check this code.
-(void)CreateTextFeildOnRun
{
if (tag ==0)
{
textPosY = 420;
}
for ( i =tag; i<= tag; i++)
{
Txt_New_Estimated = [[UITextField alloc]initWithFrame:CGRectMake(360, textPosY , 130, 65)];
Txt_New_Estimated.delegate = self;
Txt_New_Estimated.text=#"";
//[Txt_New_Estimated setTag:1234];
Txt_New_Estimated.tag = i;
Txt_New_Estimated.clearButtonMode = UITextFieldViewModeWhileEditing;
[Txt_New_Estimated addTarget:self action:#selector(C6Loop) forControlEvents:UIControlEventEditingDidEnd];
Txt_New_Estimated.placeholder = #"Estimated";
Txt_New_Estimated.font = [UIFont fontWithName:#"Arial" size:23];
Txt_New_Estimated.backgroundColor = [UIColor whiteColor];
Txt_New_Estimated.textAlignment = UITextAlignmentCenter;
[scrollview addSubview:Txt_New_Estimated];
}
}
-(void)C6Loop{
Txt_New_ONU.text=Txt_New_Estimated.text;
[self Calculate2];
}
-(void)Calculate2{
int y14=([Txt_New_Estimated.text intValue]);
y14=n;
n=d;
c14= y14+([Txt_New_Estimated.text floatValue]);
n = c14;
[self addest];
}
-(void)addest{
float c1= ([Txt_Engring_Est.text floatValue]) + ([Txt_Weddring_Est.text floatValue]) + ([Txt_Bridal_Est.text floatValue])+ ([Txt_Veil_Est.text floatValue])+ ([Txt_Shoe_Est.text floatValue])+n;
Txt_Total_Est.text = [[NSString alloc] initWithFormat:#"%.2f",c1];
}
Thank You.
Why don't you add those TextField when created to to an NSMutableArray. something like this:
-(void)createTextFieldOnRun
{
if (tag ==0)
{
textPosY = 420;
}
for ( i =tag; i<= tag; i++)
{
UITextField *Txt_New_Estimated = [[UITextField alloc]initWithFrame:CGRectMake(360,textPosY ,130,65)];
Txt_New_Estimated.delegate = self;
//....other code..
[scrollview addSubview:Txt_New_Estimated];
[textFieldArray addObject:Txt_New_Estimated];
}
}
and when calculating do something like this:
int result = 0;
for(UITextField *field in textFieldArray) // will iterate all UITextField which was added
{
result += [field.text intValue]; //or floatValue
}
NSLog(#"the result is %d", result); //here you have sum of all the text fields' text
It doesn't matter whether you change the value or not, it will recalculate all the values.

How to get UIButtons title in an array to be shown each one by one in a timed sequence

In my program, I have a series of UIButtons in an array that I would like its title to be shown each one at a time one by one in a timed sequence after executing a function that has a while loop.
I have an IBAction attached to the buttons and when touched will call another function that will do some operation and in the end, will change the UIButtons title in that array.
The problem is that it changed the whole buttons title simultaneously after executing that method but I want the title to be shown one by one in a timed sequence.
To illustrate clearly, here are my codes:
-(IBAction)touchedButton1:(id)sender
{
[self calculateSteps:0];
}
-(void)calculateSteps:(NSUInteger)hole_index2
{
index = hole_index2;
NSNumber *tempNumber = [marblesArray objectAtIndex:index];
stones = [tempNumber intValue];
[marblesArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInt:0]];
[[buttonsArray objectAtIndex:index] setTitle:[NSString stringWithFormat:#"%d", [NSNumber numberWithInt:0].intValue] forState:UIControlStateNormal];
while(stones > 0) {
if (player == PLAYER_A && stones >= 1 && index == 6) {
NSNumber *tempNumber3 = [storeArray objectAtIndex:0];
NSUInteger tempInt3 = [tempNumber3 intValue];
tempInt3++;
[storeArray replaceObjectAtIndex:0 withObject:[NSNumber numberWithInt:tempInt3]];
[buttonPlayerA setTitle:[NSString stringWithFormat:#"%d", [NSNumber numberWithInt:tempInt3].intValue] forState:UIControlStateNormal];
stones--;
if (stones == 0) { // end in PLAYER A's store
NSLog(#"end in big hole player A");
return;
}
}
if (player == PLAYER_B && stones >= 1 && index == 12) {
NSNumber *tempNumber4 = [storeArray objectAtIndex:1];
NSUInteger tempInt4 = [tempNumber4 intValue];
tempInt4++;
[storeArray replaceObjectAtIndex:1 withObject:[NSNumber numberWithInt:tempInt4]];
[buttonPlayerB setTitle:[NSString stringWithFormat:#"%d", [NSNumber numberWithInt:tempInt4].intValue] forState:UIControlStateNormal];
stones--;
if (stones == 0) { // end in PLAYER B's store
NSLog(#"end in big hole player B");
return;
}
}
index++;
if (index >= NUM_HOLES) index = 0;
NSNumber *tempNumber2 = [marblesArray objectAtIndex:index];
tempInt2 = [tempNumber2 intValue];
tempInt2++;
[marblesArray replaceObjectAtIndex:index withObject:[NSNumber numberWithInt:tempInt2]];
NSLog(#"Number in marblesArray index: %d", [NSNumber numberWithInt:tempInt2].intValue);
[[buttonsArray objectAtIndex:index] setTitle:[NSString stringWithFormat:#"%d", [NSNumber numberWithInt:tempInt2].intValue] forState:UIControlStateNormal];
stones--;
}
}
So, I have tried to put NSTimer in the calculateSteps method and also in that while loop but couldn't get to work. I guess maybe the while loop function fast enough that it didn't get the chance to get NSTimer to work in time.
I know it could work if I use if timer == 1, or else if timer == 2, etc as the timer increase, each button associated with it will change after that interval. However, when I tried to use for (timer == 1; timer < stones; timer++) , it doesn't show the buttons title each one by one but simultaneously after it is done with the loop. Am I wrong with my logic?
Also, I've tried to put sleep(2) in the while loop also, it works for the NSLog(#"Number in marblesArray index:...") appearing each 2 seconds but still the buttons array title still shown simultaneously after while loop completed.
I'm not sure how can I get the buttons title in that array to be shown each one by one in a timed sequence. Have been trying for 2 days but couldn't get it to work.
Appreciate if anyone out there who can help me. I don't know if it's my logic or if there's other function that can be used to solve this issue.
Thank you very much in advance.
Yes, you could used :
NSTimer
or just performSelector:withObject:afterDelay: of any NSObject subclass.
You can not use sleep or loop in main thread. It will block the HMI.
But I don't really understand your code and your explanation...
In the target selector of the timer, you could have a static int to count the number of ticks
example (very simple):
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
-(void)onTimer{
static int ticks = 0;
ticks++;
if (ticks==1) {
//TODO
} else if (ticks==2) {
//TODO
} else if (ticks==3) {
//TODO
} else {
//TODO
ticks=0;
}
}