如何计算相对于原点的 UITextView 第一个基线位置

Posted

技术标签:

【中文标题】如何计算相对于原点的 UITextView 第一个基线位置【英文标题】:How to calculate UITextView first baseline position relatively to the origin 【发布时间】:2016-03-10 16:37:51 【问题描述】:

如何计算UITextView 第一个基线位置?

我试过这样计算:

self.textView.font!.descender + self.textView.font!.leading

但是,我得到的值不正确。有什么想法、提示吗?

【问题讨论】:

descender如果偏离基线,肯定不应该参与计算。 leadinglineHeight 可能够了吗? 我想是self.textView.font?.ascender 【参考方案1】:

有一张来自苹果document的图

据我了解,font.descender + font.leading 给出了第一条基线和第二条线起点之间的距离。

如果UITextField 没有秘密填充,我会想象font.lineHeight 会给你正确的数字。


编辑

UITextFieldUITextView 共享相同的 UIFont 属性。

对于UITextView,可以额外设置一个textContainerInset

编辑 2

进一步查看UITextView 可以提供更多关于可以实现什么的线索:

它实际上有一个textContainer 属性,即NSTextContainer

NSTextContainer 类定义了一个放置文本的区域。 NSLayoutManager 对象使用一个或多个 NSTextContainer 对象来确定在哪里换行、布局文本部分等等。

并且被layoutManager使用过,理论上第一行文本顶部的填充可以被usedRectForTextContainer(_:)找到。

一旦我手头有一台 Mac,我将需要对此进行测试。 :)

【讨论】:

你在写UITextField,我在问UITextView。它还会起作用吗?问题是该图仅解释了 UIFont。 UITextView 添加自己的顶部填充。 很抱歉,他们都共享相同的font : UIFont 属性,所以我相信如果一个有效,另一个应该有效。【参考方案2】:

根据 zcui93 提供的文档,font.ascender 将为您提供字体内基线的偏移量。要获得UITextView 中字体的基线,您需要添加textContainerInset.top

extension UITextView 
    func firstBaseline() -> CGFloat 
        let font = self.font ?? UIFont.systemFontOfSize(UIFont.systemFontSize())
        return font.ascender + textContainerInset.top
    

这里有一点假设,如果没有设置字体,则默认为系统字体,但我不确定更好的猜测是什么。

在 Playground 中运行以下代码将演示效果:

class Container : UITextView 
    override func drawRect(rect: CGRect) 
        let context = UIGraphicsGetCurrentContext()
        CGContextSaveGState(context)

        let containerRect = UIEdgeInsetsInsetRect(bounds, textContainerInset)
        UIColor(red: 1, green: 0, blue: 0, alpha: 0.25).setFill()
        CGContextFillRect(context, containerRect)

        let baseline = firstBaseline()

        UIColor(red: 1, green: 0, blue: 0, alpha: 0.75).setStroke()
        CGContextSetLineWidth(context, 1)
        CGContextMoveToPoint(context, containerRect.origin.x, baseline)
        CGContextAddLineToPoint(context, containerRect.origin.x + containerRect.width, baseline)
        CGContextStrokePath(context)

        super.drawRect(rect)
    


let textView = Container(frame: CGRect(x: 0, y: 0, width: 100, height: 30))
textView.font = UIFont.systemFontOfSize(UIFont.systemFontSize())
textView.text = "My Text"

结果:

【讨论】:

左边的缩进怎么办?我找不到解决方案...【参考方案3】:

在我的例子中,我正在扩展 UITextField 类,我只是想在文本字段基线中画一条线,我成功地使用了以下块:

self.svwLine = UIView(frame: CGRectMake(0,self.frame.size.height+(self.font?.descender)!,self.frame.size.width,2))
self.svwLine.backgroundColor = UIColor.whiteColor()
self.addSubview(self.svwLine)

【讨论】:

以上是关于如何计算相对于原点的 UITextView 第一个基线位置的主要内容,如果未能解决你的问题,请参考以下文章

为啥更改 UITextView 的框架原点会完全破坏我的整个框架大小?

获取 UIElement 相对于屏幕原点所占用的矩形区域

iOS:UIView 相对于 UIWindow 的起源

输入:B相对于A的坐标(加入以A为原点,B的坐标)。 输出:B的世界坐标

如何改变 Qcustomplot 中曲线颜色相对于 x 轴的强度?

缩放和翻译后如何获得相对于画布的触摸坐标?