NSLayoutManager drawGlyphs бесконечный l oop, когда UITextView isScrollingEnabled имеет значение false - PullRequest
0 голосов
/ 16 марта 2020

У меня есть собственный 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, я ввожу бесконечный l oop, вызванный textStorage enumerateAttribute метод в drawGlyphs.

Я не понимаю, почему это происходит, а также я не знаю, как это предотвратить. Кто-то, кто знает больше об этом?

РЕДАКТИРОВАТЬ

Если я удаляю addSttributes textStorage с foregroundColor, то это работает. Так что это почему-то вызывает l oop.

1 Ответ

0 голосов
/ 19 марта 2020

Я нашел проблему, почему она приходит и бесконечна l oop. Хранилище текстов обновляет / добавляет атрибут, а затем снова уведомляет менеджера макетов.

Решение состоит в том, чтобы создать собственное хранилище текстов, например:

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()
  }
}

, и удалить линию под методом рисования в менеджере макетов. :

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