Ios 对齐NSLayoutManager的基线时出现问题
我正在开发一个自定义的Ios 对齐NSLayoutManager的基线时出现问题,ios,uiview,textkit,nslayoutmanager,nstextcontainer,Ios,Uiview,Textkit,Nslayoutmanager,Nstextcontainer,我正在开发一个自定义的UIView,它使用许多单独的NSLayoutManager对象呈现文本。(此视图的文本定位要求超出了内置文本视图类所能支持的范围。)当所布局的文本是希伯来文时,我很难获得其中一个布局的正确垂直位置。我为这篇文章的篇幅感到抱歉,但我希望尽可能多地包含相关细节 问题 以下是我试图实现的一个示例: “2”的基线与希伯来文字母“ו”(以自定义字体呈现)的基线对齐。但是,如果我将“2”的文本转换为希伯来语数字(实际上是希伯来语字母“ב”,在数字上下文中其值为2),结果如下(其中“
UIView
,它使用许多单独的NSLayoutManager
对象呈现文本。(此视图的文本定位要求超出了内置文本视图类所能支持的范围。)当所布局的文本是希伯来文时,我很难获得其中一个布局的正确垂直位置。我为这篇文章的篇幅感到抱歉,但我希望尽可能多地包含相关细节
问题
以下是我试图实现的一个示例:
“2”的基线与希伯来文字母“ו”(以自定义字体呈现)的基线对齐。但是,如果我将“2”的文本转换为希伯来语数字(实际上是希伯来语字母“ב”,在数字上下文中其值为2),结果如下(其中“ב”太高):
这里唯一的更改是文本字符串。它不是“2”
,而是“\u{05b1}”
。我希望一切都在一个共同的基线上,并希望有任何解决问题的建议(这适用于所有希伯来数字,而不仅仅是“\u{05b1}”
)
代码
(我应该提到,出于技术原因,我不能对数字和主文本使用一个NSLayoutManager
)我正试图通过垂直移动数字的渲染位置来对齐基线,方法是根据字体升幅的差异。以下是计算移位的代码:
numberFont = UIFont.systemFont(ofSize: /* some size */)
offset = fullFont.ascender - numberFont.ascender
下面是我如何为号码创建NSLayoutManager
:
var lbl = "2" // or "\u{05b1}"
let paraStyle = NSMutableParagraphStyle()
paraStyle.alignment = .center
let text = NSTextStorage(
string: lbl,
attributes: [NSFontAttributeName: numberFont,
NSParagraphStyleAttributeName: paraStyle]
)
let layout = NSLayoutManager()
text.addLayoutManager(layout)
let container = NSTextContainer(
size: CGSize(width: /* some fixed width */, height: bounds.height - offset)
)
container.lineFragmentPadding = 0
layout.addTextContainer(container)
let x = ... // irrelevant
let origin = CGPoint(x: x, y: bounds.minY + offset)
稍后,我将使用以下方法渲染文本:
let range = layout.glyphRange(for: layout.textContainers[0])
layout.drawGlyphs(forGlyphRange: range, at: origin)
主文本使用相同的逻辑处理,但没有偏移量(当然还有不同的字体)。这对阿拉伯数字(如“2”)很有效,但对希伯来数字(如“ב”)无效
进一步信息
对于上面的图像,字体大小(.pointSize
)和上升(.ascender
)属性是:
尺寸:文本=14.3890409469604;数字=8.63342465753425上升:text=16.159567469731;数字=8.22030179452 我还生成了一些关于布局的诊断信息,但是这些数字对我来说没有多大意义。以下是打印信息的代码:
size = text.size()
mgr = NSLayoutManager()
text.addLayoutManager(mgr)
container = NSTextContainer(
size: CGSize( width: CGFloat.greatestFiniteMagnitude,
height: CGFloat.greatestFiniteMagnitude))
container.lineFragmentPadding = 0
mgr.addTextContainer(container)
mgr.ensureLayout(for: container)
range = mgr.glyphRange(for: container)
print("label:", lbl)
print(" text size:", size)
print(" bounds:", mgr.boundingRect(forGlyphRange: range, in: container))
以下是两个文本(“2”和“\u{05d1}”)的结果:
标签:2文本大小:(5.3958904109589,10.3027782534247)
界限:(0.0,0.0,5.3958904109589,10.3027782534247)
标签:ב
文本大小:(4.67931616438356,9.19459726027397)
界限:(-1.88208657534247,--0.578439452054793,9.5054005479452,9.77303671232876) 关于这件事,有几件事让我感到困惑:
- 希伯来文文本的边界从x和y的负值开始。负x源可能与希伯来语是从右向左的脚本有关,但是负y源呢
- 报告的布局大小是边界高度和边界的y起点或(可能更准确地说)容器中文本底部的代数和,而不是实际的总体大小。
NSAttributedString.size()是否已损坏
- 这些数字似乎都不能解释“2”和“\u{05d1}”垂直位置的视觉差异
“\u{05d1}”
降低到它应该在的位置。经过一段时间的反复思考,这导致了一个可接受的解决方案:在“\u{05d1}”
之前添加一个零宽度的空格(“\u{200b}”
)。虽然这解决了让我的屏幕看起来正确的问题,但我肯定想知道发生了什么,为什么这样的混乱是必要的。我喜欢拼图。你能组织一个小项目或操场来证明这个问题吗?我已经通读了有属性的字符串指南,但没有任何东西向我跳出来。