ios - Align baselines with characters in large line heights with Text Kit -
when draw attributed string fixed line height text kit, characters aligned bottom of line fragment. while make sense on 1 line characters varying in size, breaks flow of text multiple lines. baselines appear decided largest descender each line.
i've found article people behind sketch explaining exact problem in bit more detail , showing solution does, not explaining how achieved this.
when showing 2 lines large line height, result far ideal:
the code i'm using:
let smallfont = uifont.systemfont(ofsize: 15) let bigfont = uifont.systemfont(ofsize: 25) let paragraphstyle = nsmutableparagraphstyle() paragraphstyle.minimumlineheight = 22 paragraphstyle.maximumlineheight = 22 var attributes = [ nsfontattributename: smallfont, nsparagraphstyleattributename: paragraphstyle ] let textstorage = nstextstorage() let textcontainer = nstextcontainer(size: cgsize(width: 250, height: 500)) let layoutmanager = nslayoutmanager() textstorage.append(nsattributedstring(string: "it long established fact reader ", attributes:attributes)) attributes[nsfontattributename] = bigfont textstorage.append(nsattributedstring(string: "distracted", attributes:attributes)) attributes[nsfontattributename] = smallfont textstorage.append(nsattributedstring(string: " readable content of page when looking @ layout.", attributes:attributes)) layoutmanager.addtextcontainer(textcontainer) textstorage.addlayoutmanager(layoutmanager) let textview = uitextview(frame: self.view.bounds, textcontainer:textcontainer) view.addsubview(textview)
i managed working, had drop support ios 8 , macos 10.10 unfortunately.
if implement following delegate call of nslayoutmanager
, decide baselineoffset
each line fragment:
optional func layoutmanager(_ layoutmanager: nslayoutmanager, shouldsetlinefragmentrect linefragmentrect: unsafemutablepointer<cgrect>, linefragmentusedrect: unsafemutablepointer<cgrect>, baselineoffset: unsafemutablepointer<cgfloat>, in textcontainer: nstextcontainer, forglyphrange glyphrange: nsrange) -> bool
when nstextstorage
created , each subsequent change, enumerate used font, calculate it's default line height (nslayoutmanager.defaultlineheightforfont()
) , store biggest line height. in implementation of above mentioned delegate method check current line height of nsparagraphstyle
provided line fragment , align font's line height within value. there baseline offset can calculated knowledge baseline sits between font's ascender
, descender
. update baselineoffset
value baselineoffset.memory(newoffset)
, should aligned you'd like.
note: i'm not going in detail actual code used implement because i'm not sure i'm using right values throughout these calculations. might update in near future when whole approach tried , proven.
update: implementation of adjusting baseline. every time textcontainer changes recalculate biggest line height , biggest descender. in layout manager's delegate function:
var baseline: cgfloat = (linefragmentrect.pointee.height - biggestlineheight) / 2 baseline += biggestlineheight baseline -= biggestdescender baseline = min(max(baseline, 0), linefragmentrect.pointee.height) baselineoffset.pointee = floor(baseline)
Comments
Post a Comment