【问题标题】:Is this a UITextView transparency bug?这是 UITextView 透明度错误吗?
【发布时间】:2018-08-24 09:23:34
【问题描述】:

这个问题与a problem I had yesterday 有关,我应该能够创建一个解决方法。当我进一步调查时,我发现它发生的范围比我最初想象的要广泛。我之前只在包含至少一个换行符的显示文本中注意到它,但下面的情况并非如此。

问题似乎是由于使用 NSLayoutManager 的 boundingRect 方法来获取(除其他外)单个字符宽度,然后使用这些宽度来设置字符的 UITextView 框架宽度属性。这样做显然会导致文本视图的 backgroundColor 设置为 UIColor.clear 被忽略(即背景变得不透明)。下面的 Playground 代码重现了该问题,以 红色文本 显示,并以 黑色 显示了使用常量作为宽度的解决方法。字距越紧,效果越明显。

这是一个错误吗?还是其他原因造成的怪癖?

//: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport

class MyViewController : UIViewController {

    override func loadView() {

        let view = UIView()
        view.bounds = CGRect(x: -100, y: -100, width: 200, height: 200)
        view.backgroundColor = .white

        let str = "..T.V.W.Y.."

        let strStorage = NSTextStorage(string: str)
        let layoutManager = NSLayoutManager()
        strStorage.addLayoutManager(layoutManager)
        let textContainer = NSTextContainer(size: view.bounds.size)
        textContainer.lineFragmentPadding = 0.0
        layoutManager.addTextContainer(textContainer)

        let strArray = Array(str)

        struct CharInfo {
            var char: Character
            var origin: CGPoint?
            var size: CGSize?
        }

        var charInfoArray = [CharInfo]()

        for index in 0..<str.count {

            charInfoArray.append(CharInfo.init(char: strArray[index], origin: nil, size: nil))
            let charRange = NSMakeRange(index, 1)
            let charRect = layoutManager.boundingRect(forGlyphRange: charRange, in: textContainer)
            charInfoArray[index].origin = charRect.origin
            charInfoArray[index].size = charRect.size
        }

        for charInfo in charInfoArray {

            let textView0 = UITextView()
            textView0.backgroundColor = UIColor.clear // Ignored in this case!!
            textView0.text = String(charInfo.char)
            textView0.textContainerInset = UIEdgeInsets.zero
            let size0 = charInfo.size!
            textView0.frame = CGRect(origin: charInfo.origin!, size: size0)
            textView0.textContainer.lineFragmentPadding = CGFloat(0.0)
            textView0.textColor = UIColor.red
            view.addSubview(textView0)

            let textView1 = UITextView()
            textView1.backgroundColor = UIColor.clear // Required
            textView1.text = String(charInfo.char)
            textView1.textContainerInset = UIEdgeInsets.zero
            var size1 = charInfo.size!
            size1.width = 20 // But changing .height has no effect on opacity
            textView1.frame = CGRect(origin: charInfo.origin!, size: size1)
            textView1.frame = textView1.frame.offsetBy(dx: 0, dy: 20)
            textView1.textContainer.lineFragmentPadding = CGFloat(0.0)
            textView1.textColor = UIColor.black
            view.addSubview(textView1)
        }

        self.view = view
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

【问题讨论】:

    标签: swift uitextview nslayoutmanager


    【解决方案1】:

    这似乎是一个错误,但它与 NSLayoutManager 的实例方法 boundingRect(forGlyphRange:in:) 有关。它只是看起来可能是透明度变化。

    根据Apple's documentation,boundingRect(forGlyphRange:in:) 应该是“[返回] 单个边界矩形(在容器坐标中),包含在给定字形范围内绘制在给定文本容器中的所有字形和其他标记,包括在其线片段矩形和文本属性(例如下划线)之外绘制的字形。”但这不是它正在做的事情。

    在这种情况下,由于字距调整,每个 boundingRect 的宽度都会减少下一个字形向左移动的量。您可以对此进行测试,例如,使用 str = "ToT" 并在设置后立即添加 print(size0.width)。你会得到这个:

    6.0         // "T"; should have been 7.330078125
    6.673828125 // "o"
    7.330078125 // "T"
    

    在修复此错误之前,解决方法是单独计算每个字符的字形大小。

    【讨论】:

      猜你喜欢
      • 2012-02-27
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      • 1970-01-01
      • 2013-09-24
      • 1970-01-01
      • 2017-01-11
      • 2015-12-01
      相关资源
      最近更新 更多