Attributed text, replace a specific font by another using swift -
i'm using attributed text in uitextview. text contain many fonts.
i'm looking way replace particular font one.
any swift approach this? :)
my code in objective-c, since use both cocoatouch, should same logic.
the method use enumerateattribute:inrange:options:usingblock:
nsfontattributename
.
there point isn't discussed: how recognize font 1 searched. looking familyname
, fontname
(property of uifont
? in same family, font may lot different , may want search 1 matching same name. i've discussed once font names here. may found interesting in case. note there methods (that didn't know @ time) can bold name of font if available (or italic, etc.)
the main code in objective-c one:
[attrstring enumerateattribute:nsfontattributename inrange:nsmakerange(0, [attrstring length]) options:0 usingblock:^(id value, nsrange range, bool *stop) { uifont *currentfont = (uifont *)value; //font applied in range if ([self isfont:currentfont sameas:searchedfont]) //this can tricky { [attrstring addattribute:nsfontattributename value:replacementfont range:range]; } }];
possible change/adaptation according needs: change font, not size:
[attrstring addattribute:nsfontattributename value:[uifont fontwithname:replacefontname size:currentfont.pointsize]; range:range];
sample test code:
uifont *replacementfont = [uifont boldsystemfontofsize:12]; uifont *searchedfont = [uifont fontwithname:@"helvetica neue" size:15]; uifont *normalfont = [uifont italicsystemfontofsize:14]; nsmutableattributedstring *attrstring = [[nsmutableattributedstring alloc] initwithstring:@"lorem ipsum dolor sit amet,"]; nsattributedstring *attrstr1 = [[nsattributedstring alloc] initwithstring:@"consectetuer adipiscing elit." attributes:@{nsfontattributename:searchedfont, nsforegroundcolorattributename:[uicolor redcolor]}]; nsattributedstring *attrstr2 = [[nsattributedstring alloc] initwithstring:@" aenean commodo ligula eget dolor." attributes:@{nsfontattributename:normalfont}]; nsattributedstring *attrstr3 = [[nsattributedstring alloc] initwithstring:@" aenean massa." attributes:@{nsfontattributename:searchedfont}]; nsattributedstring *attrstr4 = [[nsattributedstring alloc] initwithstring:@"cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. nulla consequat massa quis enim."]; [attrstring appendattributedstring:attrstr1]; [attrstring appendattributedstring:attrstr2]; [attrstring appendattributedstring:attrstr3]; [attrstring appendattributedstring:attrstr4]; nslog(@"attrstring: %@", attrstring); [attrstring enumerateattribute:nsfontattributename inrange:nsmakerange(0, [attrstring length]) options:0 usingblock:^(id value, nsrange range, bool *stop) { uifont *currentfont = (uifont *)value; if ([self isfont:currentfont sameas:searchedfont]) { [attrstring addattribute:nsfontattributename value:replacementfont range:rangeeffect]; } }]; nslog(@"attrstring changed: %@", attrstring);
with solution of @tigercoding, here possible code:
nsinteger location = 0; while (location < [attrstring length]) { nsrange rangeeffect; nsdictionary *attributes = [attrstring attributesatindex:location effectiverange:&rangeeffect]; if (attributes[nsfontattributename]) { uifont *font = attributes[nsfontattributename]; if ([self isfont:font sameas:searchedfont]) { [attrstring addattribute:nsfontattributename value:replacementfont range:rangeeffect]; } } location+=rangeeffect.length; }
as side note: few optimization test (but need research). think few example if apply same attributes 2 consecutive range, nsattributedstring
"appends them" one, in case may afraid apply same effect consecutively. question if have @{nsfontattributename:font1, nsforegroundcolorattributename:color1}
range 0,3 , @{nsfontattributename:font1, nsforegroundcolorattributename:color2}
range 3,5 enumerateattribute:inrange:options:usingblock:
return range 0,5? faster enumerating each indexes?
Comments
Post a Comment