How to limit text input and count characters? - objective-c

I have a text field and I want to limit the text that can be entered to 160 chars. Besides I need a counter to get the current text length.
I solved it using a NSTimer:
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self
selector:#selector(countText)
userInfo:nil
repeats:YES];
And I display the length this way:
-(void)countText{
countLabel.text = [NSString stringWithFormat:#"%i",
_textEditor.text.length];
}
This is not the best counter solution, because it depends on time and not on keyUp event. Is there a way to catch such an event and triggere a method?
The othere thing is, is it possible to block/limit text input, e.g. by providing a max length parameter on the text field?

This is (or should be) the correct version of the delegate method:
- (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
// "Length of existing text" - "Length of replaced text" + "Length of replacement text"
NSInteger newTextLength = [aTextView.text length] - range.length + [text length];
if (newTextLength > 160) {
// don't allow change
return NO;
}
countLabel.text = [NSString stringWithFormat:#"%i", newTextLength];
return YES;
}

implement some of UITextFieldDelegate protocol methods
_textEditor.delegate = self;
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
int len = [textField.text length];
if( len + string.length > max || ){ return NO;}
else{countLabel.text = [NSString stringWithFormat:#"%i", len];
return YES;}
}

you can use the delegate method
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
if(textField.length < max){
return NO;
}else return YES;
}
and set the max length and return NO.

Use following code to limit the characters in UITextField, following code accepts 25 characters in UITextField.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
NSUInteger newLength = [textField.text length] + [string length] - range.length;
return (newLength > 25) ? NO : YES;
}

Related

how to access in another class in objective -c

I have an if statement in MessagingKeyServerResponse() in objective -c, like bellow:
if (![_support_long_messages boolValue]) {
[self showAlert];
}
and in another class ContactMessagesViewController () in objective -c I have a function to limit my textfield .
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSUInteger newLength = [textView.text length] + [text length] - range.length;
return (newLength > 1000) ? NO : YES;
}
what i am trying to do is: in my if statement I would like to add function above to limit in my if statement the characters of textfield to 160 any help appreciate .

UITextField input mask?

http://sublime.nyasha.me/admin/form_masks.html
I use this technique to achieve nice results with html/css/java etc, but how does one achieve this in objective-c?
I've read so far about number formatting, but how can I literally have it so when the content is editable it displays the formatted version as they're typing and doesn't allow them to exceed .length in certain areas.
My example I need to use it for is
00:00:00 or 00h:00m:00s so when edited it will achieve __:__:__ or __h:__m:__s I've been scraping through the interwebs and cannot find such a technique, so far I've considered programatically doing something like this..
3x UITextField
1x UILabel
if (editing is commenced && value changed) {
if (.length == 2) {
Move onto next UITextField;
}
}
And display the UILabel Masked over the textfields, but also customise the textfields so 3 appears to be one.
-- EDIT
//Programming the Textfield Mask
-(void)reformatAsCardNumber:(UITextField *)textField
{
NSUInteger targetCursorPosition =
[textField offsetFromPosition:textField.beginningOfDocument
toPosition:textField.selectedTextRange.start];
NSString *cardNumberWithoutSpaces =
[self removeNonDigits:textField.text
andPreserveCursorPosition:&targetCursorPosition];
if ([cardNumberWithoutSpaces length] > 6) {
[textField setText:previousTextFieldContent];
textField.selectedTextRange = previousSelection;
return;
}
NSString *cardNumberWithSpaces =
[self insertSpacesEveryFourDigitsIntoString:cardNumberWithoutSpaces
andPreserveCursorPosition:&targetCursorPosition];
textField.text = cardNumberWithSpaces;
UITextPosition *targetPosition =
[textField positionFromPosition:[textField beginningOfDocument]
offset:targetCursorPosition];
[textField setSelectedTextRange:
[textField textRangeFromPosition:targetPosition
toPosition:targetPosition]
];
}
-(BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string
{
previousTextFieldContent = textField.text;
previousSelection = textField.selectedTextRange;
return YES;
}
- (NSString *)removeNonDigits:(NSString *)string
andPreserveCursorPosition:(NSUInteger *)cursorPosition
{
NSUInteger originalCursorPosition = *cursorPosition;
NSMutableString *digitsOnlyString = [NSMutableString new];
for (NSUInteger i=0; i<[string length]; i++) {
unichar characterToAdd = [string characterAtIndex:i];
if (isdigit(characterToAdd)) {
NSString *stringToAdd =
[NSString stringWithCharacters:&characterToAdd
length:1];
[digitsOnlyString appendString:stringToAdd];
}
else {
if (i < originalCursorPosition) {
(*cursorPosition)--;
}
}
}
return digitsOnlyString;
}
- (NSString *)insertSpacesEveryFourDigitsIntoString:(NSString *)string
andPreserveCursorPosition:(NSUInteger *)cursorPosition
{
NSMutableString *stringWithAddedSpaces = [NSMutableString new];
NSUInteger cursorPositionInSpacelessString = *cursorPosition;
for (NSUInteger i=0; i<[string length]; i++) {
if ((i>0) && ((i % 2) == 0)) {
[stringWithAddedSpaces appendString:#":"];
if (i < cursorPositionInSpacelessString) {
(*cursorPosition)++;
}
}
unichar characterToAdd = [string characterAtIndex:i];
NSString *stringToAdd =
[NSString stringWithCharacters:&characterToAdd length:1];
[stringWithAddedSpaces appendString:stringToAdd];
}
return stringWithAddedSpaces;
}
Then to call it
[_answerTextField addTarget:self
action:#selector(reformatAsCardNumber:)
forControlEvents:UIControlEventEditingChanged];
I need the pre-determined text such as __:__:__ or preferably __h:__m:__s so when you start typing you get 00h:0_m:__ as you fill out.
As right now, I get `` then when I start typing I get 00:0 etc..
Use the textFieldShouldChange method to modify the input / move the cursor as you see fit BEFORE it is updated on the screen
it is in UITextFieldDelegate:
textField:shouldChangeCharactersInRange:replacementString:
Asks the delegate if the specified text should be changed.
The text field calls this method whenever the user types a new character in the text field or deletes an existing character.
in addition there is also textDidChange in the delegate which works AFTER the text is shown
these are DELEGATE methods so you have to become the textField's delegate:
//1 conform to the delegate
#interface MyViewController <UITextFieldDelegate>
then
//2 set yourself as delegate (can also be done through IB)
textView.delegate = self;

Allow only alpha numeric characters in UITextView

Is there anyway i can allow user to enter only alpha numeric characters in a text view and no other character.
EDIT:
Tried,
if ([_txtView.text rangeOfCharacterFromSet:alphaSet].location != NSNotFound)
{
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Hello" message:#"Only alpha numeric characters are allowed" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return;
}
but this only works for some of the times
Thanks!!
You can achieve that using [[[NSCharacterSet alphanumericCharacterSet] invertedSet]. This method will return a character set containing only characters that don’t exist in the receiver.
NSCharacterSet *charactersToBlock = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
//Conform UITextField delegate and implement this method.
- (BOOL)textField:(UITextField *)field shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)characters
{
return ([characters rangeOfCharacterFromSet:charactersToBlock].location == NSNotFound);
}
Try this:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (textField == txtWebsite) {
NSCharacterSet *set = [NSCharacterSet characterSetWithCharactersInString:#"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 "];
if ([string rangeOfCharacterFromSet:set].location != NSNotFound) {
return YES;
}
else {
return NO;
}
}
else {
return YES;
}
}
write code in delegate method of uitextfield.
set delegate for textview and override/implement test should change in range method
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
NSCharacterSet *alphaSet = [NSCharacterSet alphanumericCharacterSet];
BOOL valid = [[text stringByTrimmingCharactersInSet:alphaSet] isEqualToString:#""];
return valid;
}
Equivalent Swift 3 version of the answer provided by #user1113101
Though it's late to answer and there are other simple and great approaches, but this answer might be useful to someone.
This is simple and worked like a charm for me.
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
/// 1. replacementText is NOT empty means we are entering text or pasting text: perform the logic
/// 2. replacementText is empty means we are deleting text: return true
if text.characters.count > 0 {
var allowedCharacters = CharacterSet.alphanumerics
let unwantedStr = text.trimmingCharacters(in: allowedCharacters)
return unwantedStr.characters.count == 0
}
return true
}
Note: This will work for pasting strings into the text field as well. Pasted string will not be displayed in text field if it contains any unwanted characters.
// Add this in ViewDidLoad or any init method
NSCharacterSet *blockedCharacters = [[[NSCharacterSet alphanumericCharacterSet] invertedSet] retain];
then Set your textfield's delegate in nib file .
- (BOOL)textField:(UITextField *)field shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)characters
{
return ([characters rangeOfCharacterFromSet:blockedCharacters].location == NSNotFound);
}
Or there is another way in shouldChangeCharactersInRange method. You can check
{
NSString *stringPlace = #"[a-z A-Z]*";
NSPredicate *testPlace = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", stringPlace];
BOOL matches = [testPlace evaluateWithObject:string];
if (!matches && string.length > 5)
{
return NO;
}
return YES;
}

UITextView, how do I remove the return key:linefeed?

I want to remove the linefeed that was entered in by the return key. But when I do the following it remove the last character from the text. Why?
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
{
NSLog(#"%d %d %# %#",range.location,range.length, text, [textView text]);
if ( [text isEqualToString:#"\n"] ) {
NSString *s = [textView text];
s = [s substringToIndex:[s length] - 1]; // <------------
[tvText setText:[NSString stringWithFormat:#"%#\n>>",s]];
}
return YES;
}
I want the result to look like:
>>name
>>yoda
>> <---- cursor is moved to the right of ">>"
I think you can do something like this,
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
{
NSLog(#"%d %d %# %#",range.location,range.length, text, [textView text]);
if ( [text isEqualToString:#"\n"] ) {
[tvText setText:[NSString stringWithFormat:#"%#\n>>",tvText.text]];
return NO;
}
return YES;
}
Or maybe after your reading string in line and put it to some substring:
string = [string stringByReplacingOccurrencesOfString:#"\n;" withString:#""];
shouldChangeTextInRange is part of the UITextViewDelegate, and is called before the new text is changed in the textView. Therefore, you could just do this:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text;
{
if ([text isEqualToString:#"\n"])
{
return NO;
}
return YES;
}
Use this for better solution as it won't allow user to post any blank message in any case.
//These for loops will remove the spaces and new line characters from start and end of the string
//&&//
NSMutableString *temp = [[NSMutableString alloc] initWithString:posttextview.text];
//Remove spaces and new line characters from start
for(int i = 0; i < yourtext.length; i++)
{
NSString *temp1 = [NSMutableString stringWithString:[temp substringWithRange:NSMakeRange(0,1)]];
if([temp1 isEqualToString:#"\n"] || [temp1 isEqualToString:#" "])
{
[temp deleteCharactersInRange:NSMakeRange(0,1)];
}
else
{
break;
}
}
yourtext.text = temp;
//Remove spaces and new line characters from end
for(int i = 0; i < yourtext.length; i++)
{
NSString *temp1 = [NSMutableString stringWithString:[temp substringWithRange:NSMakeRange(posttextview.text.length - 1,1)]];
if([temp1 isEqualToString:#"\n"] || [temp1 isEqualToString:#" "])
{
[temp deleteCharactersInRange:NSMakeRange(posttextview.text.length - 1,1)];
yourtext.text = temp;
}
else
{
break;
}
}
yourtext.text = temp;
//**//
The problem is that the time shouldChangeCharactersImRange is called, the new text is not actually changed yet (that's why it's not named didChangeCharactersInRange...). So in case you encounter a newline, don't trick with the substrings, just store/process the string the text view contains so far, and return NO.
First add the UITextViewDelegate in your .h file
#interface YourClass : UITextField <UITextFieldDelegate> {
}
then implement the delegate method
-(BOOL)shouldChangeCharactersInRange:replacementString:

How to stop user from inputting text in the text field in the certain range.?

I have a doubt that how can I stop user from inputting anything in the text field after he enter 8 digits? Meaning the keyboard will be disable after the text field length reaches 8 digits , but if the user deletes any digit, the keyboard enable again?
Here is the code. Please help me out, thanks in advance. Currently, it only stops until 8 digits, but it does not allow me to delete anymore.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSCharacterSet *charSet = [NSCharacterSet characterSetWithCharactersInString:DIGIT_CHARSET];
NSString *text = [string stringByTrimmingCharactersInSet:[charSet invertedSet]];
if ([textField.text length] == 8) {
return NO;
}else
{
return [text isEqualToString:string];
}
}
try this in your code. it will not Allow to write any digits after 8, but if you delete then it will allow you to write the digits untill it is 8.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
if (range.location > 7)
return NO;
else
return YES;
}
You need to check length of changed text in textField.
NSString* changedText = [textField.text stringByReplacingCharactersInRange: range withString: string];
if ([changedText length] >= 8)
return NO;