ios - Highlight just the text in a UILabel -
i'm attempting set background color/highlight text within uilabel. issue line breaks , spaces added uilabel keep text centered being highlighted.

notice spacing before last line in uilabel highlighted. also, beginning , end of new lines highlighted.
i'm creating example above following code:
-(void)createsomelabel { // create , position label uilabel *somelabel = [[uilabel alloc] initwithframe:cgrectmake(0, 0, self.view.frame.size.width - 40, self.view.frame.size.height - 300)]; somelabel.center = cgpointmake(self.view.frame.size.width / 2, self.view.frame.size.height / 2); somelabel.textalignment = nstextalignmentcenter; somelabel.textcolor = [uicolor whitecolor]; somelabel.linebreakmode = nslinebreakbywordwrapping; somelabel.numberoflines = 0; [self.view addsubview:somelabel]; // string different lengths time nsstring *somelongstring = @"here long amount of text going wordwrap/line break , don't want highlight spacing. want highlight words , single space before/after word"; // create attributed string nsmutableattributedstring *somelongstringattr=[[nsmutableattributedstring alloc] initwithstring:somelongstring attributes:nil]; // apply background color [somelongstringattr addattribute:nsbackgroundcolorattributename value:[uicolor colorwithwhite:0 alpha:0.25] range:nsmakerange(0, somelongstringattr.length)]; // set text of label somelabel.attributedtext = somelongstringattr; } the output i'd achieve highlight text , spaces between words if there 1 space. length of text , size of uilabel different hard coding solution not option unfortunately.
it seemed me line break problem. idea try , know when uilabel add line break , remove character range of characters being highlighted.
it appears can't ask uilabel line breaks going can check size of nsstring when add label. using information can increment through each character checking height, , when height changes know have new line.
i have made example takes label's string , separates individual lines appear in uilabel. once have each line, set background color on each line instead of whole string. eliminates , background colors being set on line breaks.
there better solutions, , 1 optimized better performance, it's starting point , appears work.

- (void)createsomelabel { // create , position label uilabel *somelabel = [[uilabel alloc] initwithframe:cgrectmake(0, 0, self.view.frame.size.width - 40, self.view.frame.size.height - 300)]; somelabel.center = cgpointmake(self.view.frame.size.width / 2, self.view.frame.size.height / 2); somelabel.textalignment = nstextalignmentcenter; somelabel.textcolor = [uicolor whitecolor]; somelabel.linebreakmode = nslinebreakbywordwrapping; somelabel.numberoflines = 0; [self.view addsubview:somelabel]; // string different lengths time nsstring *somelongstring = @"here long amount of text going wordwrap/line break , don't want highlight spacing. want highlight words , single space before/after word"; // create attributed string nsmutableattributedstring *somelongstringattr=[[nsmutableattributedstring alloc] initwithstring:somelongstring attributes:nil]; // idea here figure out uilabel automatically make line break , each line of text separately. // temporarily set label string can guess uilabel naturally puts line breaks. [somelabel settext:somelongstring]; // array of each individual line uilabel present it. nsarray *alllines = getlinesforlabel(somelabel); [somelabel settext:@""]; // loop through each line of text , apply background color text within range. // way, no whitespace / line breaks highlighted. __block int startrange = 0; [alllines enumerateobjectsusingblock:^(nsstring *line, nsuinteger idx, bool *stop) { // end range should length of line, minus 1 whitespace. // if on final line, there no more line breaks use whole line length. nsuinteger endrange = (idx+1 == alllines.count) ? line.length : line.length-1; // apply background color [somelongstringattr addattribute:nsbackgroundcolorattributename value:[uicolor colorwithwhite:0 alpha:0.25] range:nsmakerange(startrange, endrange)]; // update start range next line startrange += line.length; }]; // set text of label somelabel.attributedtext = somelongstringattr; } #pragma mark - utility functions static nsarray *getlinesforlabel(uilabel *label) { // text label nsstring *labeltext = label.text; // create array hold lines of text nsmutablearray *alllines = [nsmutablearray array]; while (yes) { // length of current line of text int length = getlengthoftextinframe(label, labeltext) + 1; // add line of text array [alllines addobject:[labeltext substringtoindex:length]]; // adjust label text labeltext = [labeltext substringfromindex:length]; // check final line if(labeltext.length<length) { [alllines addobject:labeltext]; break; } } return [nsarray arraywitharray:alllines]; } static int getlengthoftextinframe(uilabel *label, nsstring *text) { // create block getting bounds of current peice of text. cgrect (^boundingrectforlength)(int) = ^cgrect(int length) { nsstring *cuttext = [text substringtoindex:length]; cgrect textrect = [cuttext boundingrectwithsize:cgsizemake(label.frame.size.width, cgfloat_max) options:nsstringdrawinguseslinefragmentorigin attributes:@{nsfontattributename : label.font} context:nil]; return textrect; }; // frame of string 1 character int length = 1; int lastspace = 1; cgrect textrect = boundingrectforlength(length); cgfloat onelineheight = cgrectgetheight(textrect); // keep adding 1 character string until height changes, know have new line while (textrect.size.height <= onelineheight) { // if next character white space, save current length. // end of line. // not work character wrap. if ([[text substringwithrange:nsmakerange (length, 1)] isequaltostring:@" "]) { lastspace = length; } // increment length , new bounds textrect = boundingrectforlength(++length); } return lastspace; }
Comments
Post a Comment