Problem description

TextField to enter the ID number, mobile phone number, bank card number every few Spaces need to be added. Delete from the end or middle of the textField if you make a typo, and then keep the contents of the current TextField in the format of a space every few bits. This article is mainly aimed at solving this problem

To solve the above problems, we should mainly solve two points:

  1. Cursor position
  2. Position of space

The above two cases can be divided into:

  • Delete from last bit
  • Remove from the middle
  • Delete one and more at a time
  • Add from the last bit
  • Add from the middle
  • Add one and a few bits at a time

In each case, cursor position and space position are taken into account, and each addition and deletion is recalculated.

Implementation:

Let’s start with a more detailed description of 👇’s proxy method:

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Copy the code
range

ShouldChangeCharactersInRange: there are the location and length of two parameters, the location is about to be replaced the position of the length the length of the content is about to be replaced

string

The string used to replace the content in the range position

Suppose: TextField has content 1234

There are three ways to interpret string and range arguments:

  1. Deletes the last bit of the cursor: So the string is empty and the location of the range is the subscript of the content in front of the cursor is 3 and the length is 1 and the length of the deleted content is 1, and the result is that the string takes up the location of the range which is 123 and the 4 after 3 is taken up by the empty string which is deleted
  2. Cursor in the last bit delete two: operation, long press textField select 23, click delete. You can see that string is still empty, range is location=1, length=2 that is, position at subscript 1 is replaced by an empty string of length 2, 1 is left, and the so-called 23 is removed
  3. Add one: cursor in last bit. Enter a 2, range: location is 1, length is 0, the substituted content is at subscript 1 and length is empty. String is 2, so the result is a string with a subscript of 1 and a length of 0 is replaced by a string, that is, a 2 is added to the contents of the TextField, and the same applies to the contents of the range and string copied into the TextField

The point of this detail is to prepare for the next step.

Several properties and methods in the UITextInput protocol

Setting the cursor position requires the following two methods

// Get the cursor position offset from fromPosition. - (nullable UITextPosition *)positionFromPosition:(UITextPosition *)position offset:(NSInteger)offset; // create a UITextRange - (nullable UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition toPosition:(UITextPosition *)toPosition;Copy the code

Method to set the cursor position

According to the UITextInput protocol two methods can be obtained to set the cursor position method

+ (void)setCursorLocation:(UITextField *)textField withOffset:(NSInteger) offset{// offset is the position where the cursor is to be located // generates a new postion UITextPosition *newPostion = [textField positionFromPosition:textField.beginningOfDocument offset:offset] ; / / set the cursor From one point to another point if the two points Then the point the cursor in the textField. SelectedTextRange = [textField textRangeFromPosition: newPostion toPosition:newPostion]; }Copy the code

Note: In textField, there is an attribute called selectedTextRange, which is of UITextRange type and contains two values [start,end]. Through experiments, it can be found that when no text is selected, the values of start and end represent the current cursor position. When a region is selected, start and end are the selected head and tail cursor positions, respectively

You can see that an important parameter in the setCursorLocation method is the offset

Method to add whitespace

InsertString :(NSString*)string withBlankLocations:(NSArray<NSNumber *>*)locations {if(! string) {return nil;
    }
    NSMutableString* mutableString = [NSMutableString stringWithString:[string stringByReplacingOccurrencesOfString:@"" withString:@""]].for (NSNumber *location in locations) {
        if (mutableString.length > location.integerValue) {
            [mutableString insertString:@""atIndex:location.integerValue]; }}return  mutableString;
}
Copy the code

The above method iterates through the string based on the position of the space passed in, adding a space to the string at the specified position. This method is called when the text in the textField changes, such as deleting or adding strings

So here’s how to calculate the offset set the cursor and add Spaces, depending on the situation

Delete string

How to determine is to click the keyboard delete

As mentioned above

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Copy the code

Delete when string is empty in this proxy method. Range is a position that represents the position of the string. If the string is empty, range.length represents the length to delete

  1. Delete one bit if range.length == 1 if string is empty and range location is the length of the current textField.text subtracted by one location is the last character of textField.text

(1) If you delete the last bit, you do not need to set the cursor position and add a space

â‘¡ If it is not the last bit to delete a bit, it is necessary to determine whether the deletion is a space. If it is a space, it will be deleted twice

// Not the last bit NSInteger locationOffset = range.location;if (range.location < text.length && [text characterAtIndex:range.location] == ' '&& [textField.selectedTextRange isEmpty]) { [textField deleteBackward]; // Delete space locationOffset --; } [textField deleteBackward]; // Remove the character before the spaceCopy the code

The above code calls [textField deleteBackward] twice and deletes twice

In this case, you need to change the position of the space and the position of the indicator. The offset is the value of range.location

  1. Range. Length > 1 indicates that the number of bits is deleted at one time

(1) Whether to start the deletion at the last digit. If the deletion is started at the last digit, the cursor position still does not need to be set, but the space position should be set

â‘¡ If it is not the last digit to start the deletion, the cursor position needs to be calculated, and the offset is still the current range.location

Add string

How do YOU determine add?

As mentioned above

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Copy the code

This proxy method adds when string is not empty. Range is a position that represents the position of the string if string is not empty. Range. length represents the length of the string to be added

If the entered string length does not exceed the limit, add it directly to the textField and then add Spaces in the desired location

TextField insertText:string [textField insertText:string]; / / the string in the textField change needs to be set Spaces textField. Text = [self insertString: textField. Text withBlankLocations: blankLocation];Copy the code

In this case, the offset is calculated, and the cursor position is range.location + string.length, but if there is a space at the cursor position, the offset needs to be +1 as follows

NSInteger offset = range.location + string.length;
            
            for (NSNumber *location in blankLocation) {
                if (range.location == location.integerValue) {
                    offset ++;
                }
            }
            [self setCursorLocation:textField withOffset:offset];
Copy the code

Through the above several situations can solve the problem described at the beginning of the article.

I’m a Demo here

Reprint please indicate the source https://juejin.cn/post/6844903545624330247 thank you!

If the solution to your problem, please support ha!