Dynamic adaptive height processing for Uitextview

Source: Internet
Author: User

This article mainly deals with self-adapting heights.

Thinking of adaptive heights, presumably everyone knows how to use

BoundingRectWithSize:options:attributes to calculate.

Well, really, it's a weapon. The rect on which the font can be returned correctly. But for Uitextview it seems that the results calculated using this method are smaller than the actual display. Why is it?

I personally also searched on the internet a lot, but all unsatisfactory. So I think Uitextview did some extra processing, such as line height, border width also added together. Follow this clue all the way, sure enough, found a little doorway.

If you're familiar with Uitextview, you know he has a

Sizethatfits

method, which returns the Rect size of the font display correctly. Which has friends to think, since all provided this method, which is not better, save yourself to calculate. Not more directly. Good is good, but to touch to protect what occasions to use.

What happens when you use Sizethatfits.


For everyone to give a uncomfortable bug;

Believe that the majority of the Niang when most of the code found out is such.

-(void) Textviewdidchange: (Uitextview *) textview{    cgsize size = [TextView sizethatfits:cgsizemake (cgrectgetwidth (Textview.frame), maxfloat)];    CGRect frame = textview.frame;    Frame.size.height = Size.Height;    Textview.frame = frame;}
At the time of input, very normal, will automatically adjust high, no problem. But if you are not using input, but copy and paste, then the problem arises. See figure

Height set to 35 when not entered

When I copy a few lines of Chinese characters, then paste, see what will be the problem. See figure. Gee, the director of the font moved a part, when scrolling back to normal display.


Why is that? The reason is because sizethatfits is calculated when there is text. Start at 35 height. After the Chinese character input is completely finished, the height is still 35. Because there are too many fonts, scroll up the font first to display the last character when you want to display all fonts. Then call the Didchange method here because there are already fonts, and then to calculate the height. and set the height correctly. But because the font scrolls earlier. Frame is set after, and no re-layout is caused after setup.


How to solve this problem. The detailed pass will not explain. Code paste up, we learn, it is worth paying attention to the calculation of dynamic attitude which method, I hope to work for everyone. Find a lot of information to touch this. is more accurate. There is little difference with sizethatfits. (Big letters also try to see if there is a gap between the results calculated with emoji ah this did not try it.) )


Complete code: (Processed based on the font limitations of the previous article)

-(Cgsize) Getstringrectintextview: (NSString *) string Intextview: (Uitextview *) TextView; {////NSLog (@ "line height =%f container =%@,xxx =%f", self.textview.font.lineheight,self.textview.textcontainer,self.    textview.textContainer.lineFragmentPadding);    The actual TextView display when we set the width cgfloat contentwidth = cgrectgetwidth (textview.frame);                            But in fact the content needs to be removed the displayed border value cgfloat broadwith = (TextView.contentInset.left + textView.contentInset.right                            + TextView.textContainerInset.left + textView.textContainerInset.right + textview.textcontainer.linefragmentpadding/* Left margin */+ TextView.textContainer.lineFra        gmentpadding/* right margin */);                            CGFloat broadheight = (textView.contentInset.top + textView.contentInset.bottom + TextView.textContainerInset.top + textView.textContainerInset.bottom);//+self.te Xtview.textcontAiner.linefragmentpadding/*top*//*+thetextview.textcontainer.linefragmentpadding*//*there is no bottom padding*/);        Because of the normal string produced by the RECT to adapt to textview wide contentwidth-= Broadwith;        Cgsize insize = Cgsizemake (Contentwidth, maxfloat);    Nsmutableparagraphstyle *paragraphstyle = [[Nsmutableparagraphstyle alloc]init];    Paragraphstyle.linebreakmode = TextView.textContainer.lineBreakMode;        Nsdictionary *dic = @{nsfontattributename:textview.font, nsparagraphstyleattributename:[paragraphstyle copy]}; Cgsize calculatedsize = [string Boundingrectwithsize:insize options:nsstringdrawinguseslinefragmentorigin |        Nsstringdrawingusesfontleading Attributes:dic context:nil].size; Cgsize adjustedsize = Cgsizemake (Ceilf (calculatedsize.width), Calculatedsize.height + broadheight);//ceilf ( Calculatedsize.height) return adjustedsize;} -(void) Refreshtextviewsize: (Uitextview *) textview{cgsize size = [TextView sizethatfits:cgsizemake (Cgrectgetwidth ( Textview.frame), Maxfloat)];    CGRect frame = textview.frame;    Frame.size.height = Size.Height; Textview.frame = frame;} -(BOOL) TextView: (Uitextview *) TextView Shouldchangetextinrange: (nsrange) Range Replacementtext: (NSString *) text{//    For BACKSPACE Delete key open limit if (Text.length = = 0) {return YES;    } 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) {//Add dynamic calculation height cgsize size = [Self getstringrectintextview:comcatstr intextview:te        Xtview];        CGRect frame = textview.frame;        Frame.size.height = Size.Height;        Textview.frame = frame;    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) {                                               Nsinteger Steplen = substring.length;                                                   if (idx >= rg.length) {*stop = YES;//break is required to remove, improve efficiency                                               return; } trimstring = [trimstring Stringbyappendingstring:substring];                                           IDX = idx + Steplen;                                }];            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 the back is no no does not trigger didchange [self refreshtextviewsize:textview];            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]; [Self refreshtextviewsize:textview];}

All right. Done. Also for their own notes, every time on the page to deal with restrictions, always write once, the details are more involved. So directly paste the code. Next good direct copy to use. Oh. Copy is a bad habit .... Use caution if necessary. Thank you.




Dynamic adaptive height processing for Uitextview

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.