Log history of entered numbers in a simple calculator - iphone

I'm working on an update for a simple calculator app. The update includes a history display. My problem is that when I'm typing a number, the Log Display is ignoring the first number but logs perfectly all the rest. "Example", if I type 1234567 + 1234 ... the Log displays "234567 + 234". So the first number is never there when it should be.
- (IBAction)digitPressed:(UIButton*)sender;
{
NSString *digit = [[sender titleLabel] text];
NSRange range = [[display text] rangeOfString:#"."];
if (userIsInTheMiddleOfTypingANumber) {
if ( ! ([digit isEqual:#"."] && (range.location != NSNotFound)))
[display setText:[[display text]stringByAppendingString:digit]];
self.logDisplay.text = [self.logDisplay.text stringByAppendingFormat:#"%#", digit];
} else {
if ([digit isEqual:#"."]) {
[display setText: #"0."];
}
else {
[display setText:digit];
}
userIsInTheMiddleOfTypingANumber = YES;
}
}
Thanks in advance!

The reason you're loosing first digit is that if (userIsInTheMiddleOfTypingANumber) { returns false for the first time.
For the first press your variable userIsInTheMiddleOfTypingANumber is NO, thus, not going to be logged. The second call of digitPressed: will have userIsInTheMiddleOfTypingANumber = YES; and will log.

Related

UITextView Autocomplete modification

I'm currently using this HTAutocompleteTextField to fill in a UITextField with a predefined list, should A user start typing in an entry that already exists. There are a couple of problems that I've been having however. The first is that it seems to stop when a comma is typed in (but not apostrophes). I've been looking around and I'm really not sure why it's doing it. I thought at one point it could be that the comma was a different comma, like an apostrophe issue I had due to importing the list from a word document. However, it wasn't the case. The second issue is more of an addition which I'm not really sure how to implement. I also want the autosuggest to detect suggestions for words in mid string, not just from the beginning. So for instance typing in "String" would suggest "This is a String". This currently how it does the auto suggest, but I have no idea how to do the above things.
NSString *prefixLastComponent = [componentsString.lastObject stringByTrimmingCharactersInSet:space];
if (ignoreCase)
{
stringToLookFor = [prefixLastComponent lowercaseString];
}
else
{
stringToLookFor = prefixLastComponent;
}
for (NSString *stringFromReference in colorAutocompleteArray)
{
NSString *stringToCompare;
if (ignoreCase)
{
stringToCompare = [stringFromReference lowercaseString];
}
else
{
stringToCompare = stringFromReference;
}
if ([stringToCompare hasPrefix:stringToLookFor])
{
return [stringFromReference stringByReplacingCharactersInRange:[stringToCompare rangeOfString:stringToLookFor] withString:#""];
}
}
If anyone could give me any pointers on how to get this done, I'd appreciate it.
Regards,
Mike
Managed to go about solving both issues. For any one who uses this Git Repository, the reason why commas don't work when using the preset methods is because of NSArray *componentsString = [prefix componentsSeparatedByString:#","];. Remove the comma so it's NSArray *componentsString = [prefix componentsSeparatedByString:#""]; and it should work nicely. To fix the other problem where it only detects the start of words, I changed the methods a little. Here are my changes in HTAutocompleteManager.m
int i = 0;
for (NSString *stringFromReference in colorAutocompleteArray)
{
NSString *stringToCompare;
if (ignoreCase)
{
stringToCompare = [stringFromReference lowercaseString];
}
else
{
stringToCompare = stringFromReference;
}
if ([stringToCompare hasPrefix:stringToLookFor])
{
//NSLog(#"Removing String: %# atIndex: %d", [colorAutocompleteArray objectAtIndex:i], i);
[colorAutocompleteArray removeObjectAtIndex:i];
[colorAutocompleteArray insertObject:stringFromReference atIndex:0];
//NSLog(#"Adding String atIndex 0: %#", stringFromReference);
return [stringFromReference stringByReplacingCharactersInRange:[stringToCompare rangeOfString:stringToLookFor] withString:#""];
}
else if ([stringToCompare hasSuffix:stringToLookFor] && ([stringToLookFor length] >= 3)) {
return [NSString stringWithFormat:#" %#", stringFromReference];
}
else if (!([stringToCompare rangeOfString:stringToLookFor].location == NSNotFound) && ([stringToLookFor length] >= 3))
{
return [NSString stringWithFormat:#" %#", stringFromReference];
}
++i;
}
The reason for reordering the Array is because after the 3rd character is typed it will prioritise the other two if statements because they will be reached first if there is a generic term in multiple entries in the array (like "Street" in a list of locations). I know it's not necessary to have the "hasSuffix" if statement, but I left it in case someone wants to use it on it's own. Lastly, I added in a space before stringFromReference so that it doesn't look weird when there's a suggestion straight after the input text. When we exit the UITextField we remove this space like this (inside HTAutocompleteTextField.m - commitAutocompleteText):
NSString *currentText = self.text;
if ([self.autocompleteString isEqualToString:#""] == NO
&& self.autocompleteDisabled == NO)
{
if ([self.autocompleteString hasPrefix:#" "]) {
self.autocompleteString = [self.autocompleteString substringFromIndex:1];
}
self.text = [NSString stringWithFormat:#"%#", self.autocompleteString];
self.autocompleteString = #"";
[self updateAutocompleteLabel];
}
return ![currentText isEqualToString:self.text];
Hope this makes sense to anyone who's in a similar situation.
Mike

How to Append a Special Character after every 3 characters in UITextField Ex: (123-12346) like '-' i did it but issue while Clear

I am getting Phone card number form user in UI text field. The format of number is like
123-4567-890
I want that as user types 123 automatically - is inserted in UITextField same after 4567 - and so on.
I Did it using following code in UITextField delegate method:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
{
NSLog(#"***** %d",textField.text.length);
if(textField.text.length == 3)
{
textField.text = [textField.text stringByAppendingString:#"-"];
}
return YES;
}
But the Problem raised while clear the text, When we start clearing.
Last 3 digits 890 clears and then - addded, we cleared it and again added and soooo on so clearing stop at
We clear all the text at a time using
textField.clearButtonMode = UITextFieldViewModeWhileEditing; //To clear all text at a time
But our requirement is user must delete one character at a time.
How to achieve it?
During clearing replacementString should be empty #"". So replacement string should be checked also in addition to length check. Like this:
if (textField.text.length == 3 && ![string isEqualToString:#""]) {
// append -
}
USE: I have seen this somewhere in this forum, It worked for me
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSString *filter = #"###-####-###";
if(!filter) return YES;
NSString *changedString = [textField.text stringByReplacingCharactersInRange:range withString:string];
if(range.length == 1 && string.length < range.length && [[textField.text substringWithRange:range] rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:#"0123456789"]].location == NSNotFound)
{
NSInteger location = changedString.length-1;
if(location > 0)
{
for(; location > 0; location--)
{
if(isdigit([changedString characterAtIndex:location]))
break;
}
changedString = [changedString substringToIndex:location];
}
}
textField.text = filteredStringFromStringWithFilter(changedString, filter);
return NO;
}
NSString *filteredStringFromStringWithFilter(NSString *string, NSString *filter)
{
NSUInteger onOriginal = 0, onFilter = 0, onOutput = 0;
char outputString[([filter length])];
BOOL done = NO;
while(onFilter < [filter length] && !done)
{
char filterChar = [filter characterAtIndex:onFilter];
char originalChar = onOriginal >= string.length ? '\0' : [string characterAtIndex:onOriginal];
switch (filterChar) {
case '#':
if(originalChar=='\0')
{
done = YES;
break;
}
if(isdigit(originalChar))
{
outputString[onOutput] = originalChar;
onOriginal++;
onFilter++;
onOutput++;
}
else
{
onOriginal++;
}
break;
default:
outputString[onOutput] = filterChar;
onOutput++;
onFilter++;
if(originalChar == filterChar)
onOriginal++;
break;
}
}
outputString[onOutput] = '\0';
return [NSString stringWithUTF8String:outputString];
}

How to check if a UITextfield has Text in it?

I just followed a tut on making a conversion app. It was good, but I wanted to expand on it. The tut has you input a value in for Fahrenheit and then converts to Celsius. Pretty basic. So I wanted to add a Kelvin conversion as well. But the code only let you plug in a number for the Fahrenheit. So after adding the Kelvin text field, I wanted to check to see which text box had text in it. So I used the following code:
- (IBAction)convert:(id)sender
{
if ([fahrenheit isFirstResponder])
{
float x = [[fahrenheit text] floatValue];
float y = (x - 32.0f) * (5.0f/9.0f); //celcius
float z = y + 273.15f; //kelvin
[celcius setText:[NSString stringWithFormat:#"%3.2f" , y]];
[kelvin setText:[NSString stringWithFormat:#"%3.2f" , z]];
[fahrenheit resignFirstResponder];
} else if ([celcius isFirstResponder])
{
float x = [[celcius text] floatValue];
float y = 32.0f + ((9.0f/5.0f) * x); //farenheit
float z = x + 273.12f; //kelvin
[fahrenheit setText:[NSString stringWithFormat:#"%3.2f" , y]];
[kelvin setText:[NSString stringWithFormat:#"%3.2f" , z]];
[celcius resignFirstResponder];
}else if ([kelvin isFirstResponder])
{
float x = [[kelvin text] floatValue];
float y = x - 273.15f; //celcius
float z = 32.0f + ((9.0f/5.0f) * y); //farenheit
[celcius setText:[NSString stringWithFormat:#"%3.2f" , y]];
[fahrenheit setText:[NSString stringWithFormat:#"%3.2f" , z]];
[kelvin resignFirstResponder];
}
}
This allowed me to input a number in any text field and then convert. But then I decided to dismiss the keyboard. My code said to resignFirstResponder. But then the convert action did not work because now there was no first responder. Any clues as to how I can check which text box has text in it, and then do the conversions? Thanks in advance for any help.
if( [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] != nil && [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] != #"" )
{
// text field has text
// get text without white space
NSString * textWithoutWhiteSpace = [textField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
}
This is for checking textView is empty or not:-
if([textView.text isEqualToString:#""])
{
//textView is Empty
}
else
{
//textView has text
}
If you want to check it for white space as well, first remove white spaces from string then check ... like this -
NSString *trimmedString = [tV.text stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if([trimmedString isEqualToString:#""])
{
NSLog(#"textView is empty");
}
else
{
NSLog(#"textView has some value");
}
Just use the hasText method.
Example:
if(_yourTextField.hasText)
{
// Do something.
}
if(textView.text.length > 0)
{
//text present
}
else
{
//no text
}
Better solution is make all conversions on the fly, add new action to all textFields
[textField addTarget:self action:#selector(textChanged:) forControlEvents:UIControlEventEditingChanged];
Then in method textChanged: do something like this:
- (void) textChanged:(UITextField *)tf {
if (tf.text.floatValue > 0) {
if (tf == fahrenheit) {
//Do convertion for fahrenheit
}
.
.
.
//etc.
}
}
On response to Meno's answer
DO NOT USE != #""
this check for pointer equality vs String equality
use:
[string isEqualToString:#""];
If you want to know it DURING input, and probably performs actions based on this info, you shall use:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
There were a few problems in some of the other answers, like they didn't use isEqualToString, and they superfluously removed potential characters from a string that we are only interested in if it is nil or not.
I don't have enough reputation to comment, so I am posting this as an answer.
For a similar issue, I used this to check each textfield that I needed to check for being empty:
- (BOOL) isEmpty:(UITextField*) field
{
if (!(field.text) ||
([[field.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] isEqualToString: #""]))
{
return YES;
}
else
{
return NO;
}
}
If you need an NSString with white space removed:
NSString *nonWhiteSpaceString = [textfield.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
Then you could use the length as a boolean:
BOOL textFieldHasText = nonWhiteSpaceString.length;

UITextField NSString length problems while formatting NSString

I have been working on this for a few days now and I have some buzzy things going on with my textfields... and it's got to the point where I need to take a step back and hope someone with a fresh pair of eyes can shed light on the situation.
basically what I'm doing is formatting a 20 character string into sets of 5 as the user types after every 5th character a hyphen pops into the string, that works sweet.
I have a submit button that is not perusable until the 20th character is entered, this also works but where it gets CRAZY! is if you delete back one character the submit button still works.. then you delete back one more character and it doesn't work... I'm at a loss as my if statements conditions don't work like they should I specify == 23 characters and you have to hit one of the keys 24 times to get into that statement.. it makes no logical sense.
anyway if you could help me with the first question that would be great then if you have any ideas on the second question that would be great.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *separator = #"-";
int seperatorInterval = 5; //how many chars between each hyphen
NSString *originalString = [regTextField.text stringByReplacingOccurrencesOfString:separator withString:#""];
if (textField.text.length == 23 && range.length == 0){
return NO; // return NO to not change text
}
if (![originalString isEqualToString:#""] && ![string isEqualToString:#""]) {
NSString *lastChar = [regTextField.text substringFromIndex:[regTextField.text length] - 1];
int modulus = [originalString length] % seperatorInterval;
if (![lastChar isEqualToString:separator] && modulus == 0) {
regTextField.text = [regTextField.text stringByAppendingString:separator];
}
}
[self validateTextFields];
return YES; //Keep accepting input from the user
}
//Validating text field to see if Submit button can be pressed or not
-(IBAction) validateTextFields {
NSString *intString = [NSString stringWithFormat:#"%d", regTextField.text.length];
NSLog(#"Starting %#", intString);
if (regTextField.text.length < 22){
[submitButton setEnabled:NO]; //enables submitButton
}
else {
regTextField.text = [regTextField.text substringToIndex:22];
[submitButton setEnabled:YES]; //disables submitButton
}
intString = [NSString stringWithFormat:#"%d", regTextField.text.length];
NSLog(#"Done %#", intString);
}
You need to add = sign in this if statement
if (regTextField.text.length <= 22){
or just change the number to 23 either way it should work
if (regTextField.text.length < 23){

ObjC - Using NSRange, Allow User to Enter Only One decimal point -

building a simple calculator here to get my feet wet with iOS dev. I want to prohibit the entry of more than one decimal point. Put my logic in the comment.
It builds and runs with no problem, but it's not blocking the entry of more than one "." any help is appreciated. Thanks.
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [[sender titleLabel] text];
if (userIsInTheMiddleofTypingANumber) {
[display setText:[[display text] stringByAppendingString:digit]];
// if the user enters a decimal point, check if the existing display text contains a "." if not, then allow it, but if it does, do not allow it.
NSString *decimal = #".";
NSRange range = [digit rangeOfString:decimal];
if (range.location == NSNotFound) {
[display setText:digit];
}
} else {
[display setText:digit];
userIsInTheMiddleofTypingANumber = YES;
}
}
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [[sender titleLabel] text];
NSString *decimal = #".";
BOOL decimalAlreadyEntered = [display.text rangeOfString:decimal].location == NSNotFound ? NO : YES;
if (userIsInTheMiddleofTypingANumber) {
if (([digit isEqual:decimal] && !decimalAlreadyEntered) || !([digit isEqual:decimal])) {
[display setText:[[display text] stringByAppendingString:digit]];
}
}
else if (display.text isEqual:#"0" && digit == decimal){
[display setText:[[display text] stringByAppendingString:digit]];
userIsInTheMiddleofTypingANumber = YES;
}
else {
[display setText:digit];
userIsInTheMiddleofTypingANumber = YES;
}
}
I think this should work. It looks like you are appending the digit first thing in your loop, even if a decimal has been entered. I haven't tried this code in the compiler but it checks to see if a decimal has been entered first.
Don't frustrate your user. Give them feedback about what you can and cannot accept for input:
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *char = [[sender titleLabel] text];
if( [char isEqualTo:#"."] ){
[sender setEnabled:NO];
}
[display setText:[[display text] stringByAppendingString:char]];
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)replacementRange replacementString:(NSString *)replacementString {
// Re-enable the button if the decimal point is deleted
NSRange rangeForPoint = [[display.text substringWithRange:replacementRange]
rangeOfString:#"."];
if( NSNotFound != rangeForPoint.location ){
// You may also want to check that replacementString does not contain a new
// decimal point, in the case of pasted text, e.g.
[decimalPointButton setEnabled:YES];
}
}
This delegate method, textField:shouldChangeCharactersInRange:replacementString: is really the key to handling restricted input. You should also look at NSFormatter, which can take a format and validate input as the user types, using its isPartialStringValid... methods.
You might want to check an earlier post by me, which deals with sort of the same issue. I tried creating a textfield that accepts limited input (for example only numbers in the following format: 0.00). It never worked completely great (it had some bugs with currency I believe), but it might be good enough for your purposes:
Re-Apply currency formatting to a UITextField on a change event
This worked for me:
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [[sender titleLabel] text];
if (userIsInTheMiddleOfTypingANumber)
{
if (decimalEntered)
{
NSRange range = [digit rangeOfString:#"."];
if (range.location == NSNotFound)
{
[display setText:[[display text] stringByAppendingString:digit]];
}
else
{
NSLog(#"You can't enter more than one decimal");
}
}
else if (!decimalEntered)
{
NSRange range = [digit rangeOfString:#"."];
if (range.location == NSNotFound)
{
[display setText:[[display text] stringByAppendingString:digit]];
}
else
{
[display setText:[[display text] stringByAppendingString:digit]];
decimalEntered = YES;
}
}
}
else
{
decimalEntered = NO;
[display setText:digit];
userIsInTheMiddleOfTypingANumber = YES;
}
}
Try below updated code of yours
- (IBAction)digitPressed:(UIButton *)sender
{
NSString *digit = [[sender titleLabel] text];
if (userIsInTheMiddleofTypingANumber)
{
// if the user enters a decimal point, check if the existing display text contains a "." if not, then allow it, but if it does, do not allow it.
NSString *decimal = #".";
NSRange range = [digit rangeOfString:decimal];
if (range.location == NSNotFound)
{
[display setText:[[display text] stringByAppendingString:digit]];
[display setText:digit];
}
}
else
{
[display setText:digit];
userIsInTheMiddleofTypingANumber = YES;
}
}