One---Fixed length (Word limit for common uitextview input)

Source: Internet
Author: User

For a long time did not write the article, today came up to write, found that increased the markdown editor. Very good, follow-up study, today, write the article first. All right, no nonsense.

Title, I believe you see this title do not want to read the article, this has what to say, online a search a lot. Well, think of it as a search for a lot of skip, interested in watching the ...


The number of characters to limit uitextview input. Believe that everyone on the Internet to realize the most is to achieve uitextviewdelegate

-(BOOL) TextView: (Uitextview *) TextView Shouldchangetextinrange: (nsrange) Range Replacementtext: (NSString *) text;// There is a touch on the input, but for the Chinese keyboard to produce a legend selection will not trigger-(void) Textviewdidchange: (Uitextview *) textview;//when the input and the above code returns YES when the trigger. or triggered when you select a legend on the keyboard.
The first is for restricting input and the second is for dynamic calculation of the remaining word count. All right, let's just slow down. The two agents work together to limit the input.

From the simplest of beginnings. In order to facilitate the analysis, the statement

#define Max_limit_nums 100来 limit maximum input of 100 characters only

Detailed implementation code:

-(BOOL) TextView: (Uitextview *) TextView Shouldchangetextinrange: (nsrange) Range Replacementtext: (NSString *) text{        NSString *comcatstr = [Textview.text stringbyreplacingcharactersinrange:range withstring:text];        Nsinteger Caninputlen = max_limit_nums-comcatstr.length;    if (Caninputlen >= 0) {return YES;        } else {Nsinteger len = text.length + Caninputlen;                Prevents when Text.length + Caninputlen < 0 o'clock, making rg.length an illegal maximum positive number error Nsrange RG = {0,max (len,0)};                        if (Rg.length > 0) {nsstring *s = [text Substringwithrange:rg];        [TextView settext:[textview.text Stringbyreplacingcharactersinrange:range withstring:s];    } return NO;    }}-(void) Textviewdidchange: (Uitextview *) textview{nsstring *nstextcontent = Textview.text;        Nsinteger existtextnum = nstextcontent.length; if (Existtextnum > Max_limit_nums) {//intercept to the maximum position of the character nsstring *s = [NstextcontENT substringtoindex:max_limit_nums];    [TextView settext:s]; }//Do not let show negative numbers self.lbNums.text = [NSString stringwithformat:@ "%ld/%d", MAX (0,max_limit_nums-existtextnum), Max_limi T_nums];}

Final Run Effect:



How big is the picture? ^_^. You see this is not to say OK. Just submit the code?

OK, here are the simple generations above to find and fix each bug.


1. Legacy bugs (only English keyboard processing is considered)

The above code in the English keyboard basically can be normal, but if it is in Chinese (born in the Chinese ah must have to understand English) or 9 of the Palace keyboard will have what to ask is it. Is me, when the input to only one word, when the input pinyin, the problem appeared, found that pinyin output is not complete. Another problem is that when the distance from the word limit is very large, the input pinyin will find that the word count is also calculated. Originally did not enter, at this time began to calculate, there are abdominal mass times.

, in the last one, would like to enter a pinyin h beginning and did not appear in the recommended word. Which again entered the second pinyin when found not to lose, and the word count is calculated.


To the above may have a friend said, this is what the bug. There's basically no such situation. Yes, but what if it was inserted in the middle of a word. There is a possibility that this will happen.

How to deal with the resulting bug? From the analysis of the fact that the input pinyin is still in the highlighted state, which is there any way to get it. So I called in the search ...

OK, it does have such a good. Add the following code as follows:

-(BOOL) TextView: (Uitextview *) TextView Shouldchangetextinrange: (nsrange) Range Replacementtext: (NSString *) text{    Uitextrange *selectedrange = [TextView markedtextrange];    Get the highlighted part uitextposition *pos = [TextView positionFromPosition:selectedRange.start offset:0];        Get highlighted content//nsstring * SelectedText = [TextView textinrange:selectedrange]; If there is a highlight and the current word start position is less than the maximum limit, allow input if (Selectedrange && pos) {Nsinteger startoffset = [TextView Offsetfromposi        Tion:textView.beginningOfDocument ToPosition:selectedRange.start];        Nsinteger Endoffset = [TextView offsetFromPosition:textView.beginningOfDocument toPosition:selectedRange.end];                Nsrange Offsetrange = Nsmakerange (Startoffset, Endoffset-startoffset);        if (Offsetrange.location < max_limit_nums) {return YES;        } else {return NO; }} nsstring *comcatstr = [Textview.text stringbyreplacingcharactersinrange:range Withstring:texT];        Nsinteger Caninputlen = max_limit_nums-comcatstr.length;    if (Caninputlen >= 0) {return YES;        } else {Nsinteger len = text.length + Caninputlen;                Prevents when Text.length + Caninputlen < 0 o'clock, making rg.length an illegal maximum positive number error Nsrange RG = {0,max (len,0)};                        if (Rg.length > 0) {nsstring *s = [text Substringwithrange:rg];            [TextView settext:[textview.text Stringbyreplacingcharactersinrange:range withstring:s];            Since it is out of the partial interception, which must be the maximum limit.        Self.lbNums.text = [NSString stringwithformat:@ "%d/%ld", 0, (long) max_limit_nums];    } return NO;    }}-(void) Textviewdidchange: (Uitextview *) textview{uitextrange *selectedrange = [TextView markedtextrange];        Get the highlighted part uitextposition *pos = [TextView positionFromPosition:selectedRange.start offset:0];    If the highlighted part is changing in the change, do not calculate the character if (Selectedrange && pos) {return; } nsstring *nstextcontent = Textview.text;        Nsinteger existtextnum = nstextcontent.length; if (Existtextnum > Max_limit_nums) {//intercept to the maximum position of the character nsstring *s = [Nstextcontent substringtoindex:max_li                Mit_nums];    [TextView settext:s]; }//Do not let display negative port day Self.lbNums.text = [NSString stringwithformat:@ "%ld/%d", MAX (0,max_limit_nums-existtextnum), Max_ Limit_nums];}


The effect is as follows: when the pinyin input is still highlighted, the word count is no longer counted.



After the above processing, basically can support the normal, English input method keyboard character restrictions.

There may be some developers can say that the finished, and boss can say that the bug is ready. Being ready to see a blockbuster ..... The test came, and there was a bug.

Convex-^ Convex

There's a bug? (In many cases, we are not fully guided by the thought, and some scenarios are not predictable, so experience is critical)

The above code, in the input, the English can be normal restrictions and processing, but if the input characters with emoji emoji, and the user is using the Paste method is likely to be a bug. Look, put a emoji on the last one. It turns garbled? Why is it garbled? Because emoji used in iOS is UTF16 that is the placeholder is 8+8 two bytes (the length of 2, so in the calculation of the word number of an expression accounted for 2 that all expressions can only enter 50, so the calculation is a problem), equivalent to double Unicode. So in use

Substringwithrange, or Substringtoindex, can just take half the character of a emoji. Show:


Therefore, when you use the Intercept string function, you must determine whether the intercept position is emoji character. (Of course there are some unknown characters that can be pasted at the last time to intercept the problem.) Fortunately, iOS's interception of Chinese is still correct. Otherwise, you have to judge Unicode. Well, since the question is appeared, which must be resolved ah, or boss will have to make up ....

The solution is to determine whether the location of the interception is exactly emoji. A more stupid way is to determine the location of the interception, first assumed to be emoji, take the position of the first 1 characters and the current string combination (AB) and then use the emoji to determine whether the combination of characters is emoji if so, then the location of the intercept is exactly a emoji end bit. If the combination found not emoji, then to determine the intercept position and +1 string (note to determine whether the cross-border), after the combination of BC emoji regular, if the emoji is the location of the interception of the emoji split into two, so this time the actual interception should be the current intercept position + 1 This will allow the emoji to intercept the whole. If not then rest assured that the intercept location is not emoji. (There is no guarantee that it is not another double-byte)

Let's take a look at the length of the emoji output and his actual character (you can see it in TextView only with a smiley face)

    Encode    nsdata *data = [Comcatstr datausingencoding:nsnonlossyasciistringencoding];    NSString *goodvalue = [[NSString alloc] Initwithdata:data encoding:nsutf8stringencoding];        NSLog (@ "GV =%@,len =%d", goodvalue,goodvalue.length);        Decode    data = [Goodvalue datausingencoding:nsutf8stringencoding];    Goodvalue = [[NSString alloc] Initwithdata:data encoding:nsnonlossyasciistringencoding];        NSLog (@ "GV =%@,len =%d", goodvalue,goodvalue.length);

The output log is:


To solve the interception problem, I called, and I looked for a more appropriate method (which I think is good) as long as it's not used to count words, it can be efficient.

Full code:

-(BOOL) TextView: (Uitextview *) TextView Shouldchangetextinrange: (nsrange) Range Replacementtext: (NSString *) text{    Uitextrange *selectedrange = [TextView markedtextrange];    Get the highlighted part uitextposition *pos = [TextView positionFromPosition:selectedRange.start offset:0];        Get highlighted content//nsstring * SelectedText = [TextView textinrange:selectedrange]; If there is a highlight and the current word start position is less than the maximum limit, allow input if (Selectedrange && pos) {Nsinteger startoffset = [TextView Offsetfromposi        Tion:textView.beginningOfDocument ToPosition:selectedRange.start];        Nsinteger Endoffset = [TextView offsetFromPosition:textView.beginningOfDocument toPosition:selectedRange.end];                Nsrange Offsetrange = Nsmakerange (Startoffset, Endoffset-startoffset);        if (Offsetrange.location < max_limit_nums) {return YES;        } else {return NO; }} nsstring *comcatstr = [Textview.text stringbyreplacingcharactersinrange:range Withstring:texT];        Nsinteger Caninputlen = max_limit_nums-comcatstr.length;    if (Caninputlen >= 0) {return YES;        } else {Nsinteger len = text.length + Caninputlen;                Prevents when Text.length + Caninputlen < 0 o'clock, making rg.length an illegal maximum positive number error Nsrange RG = {0,max (len,0)};            if (Rg.length > 0) {nsstring *s = @ "";            Determine if only ordinary characters or ASC codes (for Chinese and Emoticons return NO) BOOL ASC = [text canbeconvertedtoencoding:nsasciistringencoding];                 if (ASC) {s = [text substringwithrange:rg];//because the ASCII code is directly taken it can be no wrong} else {                __block Nsinteger idx = 0;  __block nsstring *trimstring = @ "";//intercept the string//use the strings traversal, this method can know exactly whether each emoji is a Unicode or two [text Enumeratesubstringsinrange:nsmakerange (0, [text length]) options:nsstringenu                                   Merationbycomposedcharactersequences        Usingblock: ^ (nsstring* substring, nsrange substringrange, Nsrange Enclosingrange, bool* stop) {                                                   if (idx >= rg.length) { *stop = YES;                                               Remove the need to break, improve efficiency return;  } trimstring = [trimstring                                                                                              Stringbyappendingstring:substring];                                           idx++;                                }];            s = trimstring; //rang refers to the substitution processing from the current cursor (note that if yes is returned after this sentence is executed, the Didchange event is triggered) [TextView settext:[textview.text Stringbyrep            Lacingcharactersinrange:range Withstring:s]];            Since it is out of the partial interception, which must be the maximum limit. Self.lbNums.teXT = [NSString stringwithformat:@ "%d/%ld", 0, (long) max_limit_nums];    } return NO;    }}-(void) Textviewdidchange: (Uitextview *) textview{uitextrange *selectedrange = [TextView markedtextrange];        Get the highlighted part uitextposition *pos = [TextView positionFromPosition:selectedRange.start offset:0];    If the highlighted part is changing in the change, do not calculate the character if (Selectedrange && pos) {return;    } nsstring *nstextcontent = Textview.text;        Nsinteger existtextnum = nstextcontent.length; if (Existtextnum > Max_limit_nums) {//intercept to the maximum position of the character (because the outside section is processed at should, it is here to improve efficiency no longer judged) nsstring *s = [NS                Textcontent Substringtoindex:max_limit_nums];    [TextView settext:s]; }//Do not let display negative port day Self.lbNums.text = [NSString stringwithformat:@ "%ld/%d", MAX (0,max_limit_nums-existtextnum), Max_ Limit_nums];}

Review, the article to this, a total of resolved what easy to leave the bug

1. In, English characters are limited when entering.

2. Take emoji when the interception shows half or garbled character processing.


Well, is that the above is not considered to be more perfect. Or. As mentioned earlier, there is a problem with the calculation of the number of characters when there is a emoji, because a emoji can account for a length of 2, and the individual is 1. A friend would say that the data is just not displayed, but it doesn't affect the display. Are you sure? What, you're wrong about that, just grab a piece of emoji and plain English characters, and you'll find that when you press BACKSPACE to delete the key, it doesn't work. Why is it? The original because of the interception of emoji code part, because to prevent half of the emoji, so a emoji the original length len=2 when one calculation, the final overall length is greater than the actual length. So to ensure the most basic accuracy, adjust the interception code.

                [Text Enumeratesubstringsinrange:nsmakerange (0, [text length]) Options:nsstringenumerationbycomposedcharactersequences Usingblock: ^ (nsstring                                                                                              * substring, Nsrange substringrange, Nsrange Enclosingrange, bool* stop) {                                               Nsinteger Steplen = substring.length;                                                   if (idx >= rg.length) {*stop = YES;//break is required to remove, improve efficiency                                               return; } trimstring = [Trimstring St                                                                                              Ringbyappendingstring:substring]; IDX = idx + steplen;//here has changed, using the length of the string as a stepLong}]; 
It is basically possible to determine the length with emoji. When the length is 100, the pure emoji is 50, and if it is 50 characters, it can add up to 25 emoji.


A friend wants to think of a emoji as a character to figure out what to do with it. I suggest you use

[Text Enumeratesubstringsinrange:nsmakerange (0, [text length])                                              options: Nsstringenumerationbycomposedcharactersequences                                           usingblock: ^ (nsstring* substring, Nsrange substringrange, Nsrange Enclosingrange, bool* stop) {
This method to deal with. There are a lot of computational mixed string lengths on the Web. The processing of emoji is not correct.

Writing here basically solves the limitations of the input characters. I hope we have some help, thank you. In the process there are unexpected or unforeseen also hope that you leave a message to me. I'll do a good research and then add. Thank you.


Please continue to focus on Uitextview's dynamic adaptation to height processing.








One---Fixed length (Word limit for common uitextview input)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.