代码之家  ›  专栏  ›  技术社区  ›  Optimalist

这是UITextView透明错误吗?

  •  0
  • Optimalist  · 技术社区  · 6 年前

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

    这个问题似乎是由于使用NSLayoutManager的boundingRect方法获取(除其他外)单个字符宽度,然后使用这些宽度设置字符的UITextView帧宽度属性造成的。这样做显然会导致文本视图的backgroundColor设置为UIColor.clear被忽略(即,背景变得不透明)。下面的游乐场代码再现了该问题,如 红色文本 ,并显示在 黑色 . 紧排越紧,效果越明显。

    enter image description here

    这是虫子吗?或者是因为别的原因?

    //: 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()
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   Optimalist    6 年前

    这看起来确实是一个bug,但它与NSLayoutManager的实例方法boundingRect(forglyprange:in:)有关。仅此而已 就像是透明度的改变。

    Apple's documentation ,boundingRect(forglyprange:in:)应该是“[返回]一个单独的边界矩形(在容器坐标中),其中包含给定字形范围内在给定文本容器中绘制的所有字形和其他标记,包括在线外绘制的字形、片段矩形和下划线等文本属性。

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

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