繁体   English   中英

当 UITextView isScrollingEnabled 为 false 时 NSLayoutManager drawGlyphs 无限循环

[英]NSLayoutManager drawGlyphs endless loop when UITextView isScrollingEnabled is false

我有一个自定义的 NSLayoutManager 覆盖了这两种方法:

override func drawGlyphs(forGlyphRange glyphsToShow: NSRange, at origin: CGPoint) {
    super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin)

    let characterRange = self.characterRange(forGlyphRange: glyphsToShow, actualGlyphRange: nil)
    textStorage?.enumerateAttribute(.blur, in: characterRange, options: .longestEffectiveRangeNotRequired, using: { (value, subrange, _) in
        guard let key = value as? String, !key.isEmpty else { return }
        let blurGlyphRange = glyphRange(forCharacterRange: subrange, actualCharacterRange: nil)
        drawBlur(forGlyphRange: blurGlyphRange)
        textStorage?.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.clear], range: blurGlyphRange)
    })
}

private func drawBlur(forGlyphRange tokenGlypeRange: NSRange) {
    guard let textContainer = textContainer(forGlyphAt: tokenGlypeRange.location, effectiveRange: nil) else { return }
    let withinRange = NSRange(location: NSNotFound, length: 0)
    enumerateEnclosingRects(forGlyphRange: tokenGlypeRange, withinSelectedGlyphRange: withinRange, in: textContainer) { (rect, _) in
        let blurRect = rect.offsetBy(dx: self.textContainerOriginOffset.width, dy: self.textContainerOriginOffset.height)
        UIColor.red.setFill()
        UIBezierPath(roundedRect: blurRect, cornerRadius: 4).fill()
    }

一切正常,除了当我将 UITextView isScrollingEnabled 设置为 false 时,我进入了由 drawGlyphs 中的 textStorage enumerateAttribute 方法引起的无限循环。

我不明白为什么会发生这种情况,也不知道如何防止这种情况发生。 有人对此了解更多吗?

编辑

如果我用 foregroundColor 删除 textStorage addAttributes 那么它就可以工作了。 因此,出于某种原因,这导致了循环。

我发现了为什么它会进入和无限循环的问题。 textstorage 更新/添加属性,然后再次通知 layoutmanager。

解决方案是像这样创建自己的文本存储:

class CustomTextStorage: NSTextStorage {
  private let backingStore = NSMutableAttributedString()

  override var string: String {
    return backingStore.string
  }

  override init() {
    super.init()
  }

  required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
  }

  override func attributes(at location: Int, effectiveRange range: NSRangePointer?) -> [NSAttributedString.Key: Any] {
      return backingStore.attributes(at: location, effectiveRange: range)
  }

  override func replaceCharacters(in range: NSRange, with str: String) {
    beginEditing()
    backingStore.replaceCharacters(in: range, with:str)
    edited(.editedCharacters, range: range, changeInLength: (str as NSString).length - range.length)
    endEditing()
  }

  override func setAttributes(_ attrs: [NSAttributedString.Key: Any]?, range: NSRange) {
    beginEditing()
    backingStore.setAttributes(attrs, range: range)
    if let attrs = attrs, let _ = attrs[.blur] {
        backingStore.addAttribute(.foregroundColor, value: UIColor.clear, range: range)
    }
    edited(.editedAttributes, range: range, changeInLength: 0)
    endEditing()
  }
}

并删除layoutmanager中draw方法下的行:

textStorage?.addAttributes([NSAttributedString.Key.foregroundColor: UIColor.clear], range: blurGlyphRange)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM