drawGlyphsForGlyphRange в Swift (отображение невидимых символов). replaceGlyphAtIndex устарел

Я пытаюсь показать невидимые символы, используя класс и функцию ниже, и он работает нормально.

Но replaceGlyphAtIndex устарел в OS X 10.11, и нам нужно использовать setGlyhs()

setGlyphs(<#T##glyphs: UnsafePointer<CGGlyph>##UnsafePointer<CGGlyph>#>, properties: <#T##UnsafePointer<NSGlyphProperty>#>, characterIndexes: <#T##UnsafePointer<Int>#>, font: <#T##NSFont#>, forGlyphRange: <#T##NSRange#>)

Но у меня возникли трудности с преобразованием replaceGlyphAtIndex в setGlyphs. Может ли кто-нибудь предложить мне, как преобразовать ниже replaceGlyphAtIndex в setGlyphs ()?

Я пробовал, как показано ниже, но он падает.

let data = String(g).dataUsingEncoding(NSUTF8StringEncoding)
let cgG = UnsafePointer<CGGlyph>(data!.bytes)
self.setGlyphs(cgG, properties: nil, characterIndexes: UnsafePointer<Int>(bitPattern: characterIndex), font: font as! NSFont, forGlyphRange: NSMakeRange(glyphIndex, 1))

Может ли кто-нибудь сообщить мне, что происходит в приведенной выше строке кода?

class MyLayoutManager: NSLayoutManager {

override func drawGlyphsForGlyphRange(glyphsToShow: NSRange, atPoint origin: NSPoint) {
    if let storage = self.textStorage {
        let s = storage.string
        let startIndex = s.startIndex

        for glyphIndex in glyphsToShow.location ..< glyphsToShow.location + glyphsToShow.length {
            let characterIndex = self.characterIndexForGlyphAtIndex(glyphIndex)
            let ch = s[startIndex.advancedBy(characterIndex)]
            switch ch {
            case " ": //Blank Space
                let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
                if let font = attrs[NSFontAttributeName] {
                    let g = font.glyphWithName("period")//("periodcentered")
                    self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)


                    //                        let data = String(g).dataUsingEncoding(NSUTF8StringEncoding)
                    //                        let cgG = UnsafePointer<CGGlyph>(data!.bytes)
                    //
                    //                        self.setGlyphs(cgG, properties: nil, characterIndexes: UnsafePointer<Int>(bitPattern: characterIndex), font: font as! NSFont, forGlyphRange: NSMakeRange(glyphIndex, 1))
                }
            case "\n": //New Line
                let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
                if let font = attrs[NSFontAttributeName] {
                    let g = font.glyphWithName("logicalnot")
                    self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
                }
            case newLineUniCodeStr:
                let attrs = storage.attributesAtIndex(characterIndex, effectiveRange: nil)
                if let font = attrs[NSFontAttributeName] {
                    let g = font.glyphWithName("logicalnot")
                    self.replaceGlyphAtIndex(glyphIndex, withGlyph: g)
                }
            default:
                break
            }
        }
    }
    super.drawGlyphsForGlyphRange(glyphsToShow, atPoint: origin)
}

}


person Shiva Kumar    schedule 14.09.2016    source источник


Ответы (1)


Я нашел другой способ отображения глифов. (Публикация моего кода ниже, так как он может быть полезен другим)

override func drawGlyphsForGlyphRange(glyphsToShow: NSRange, atPoint origin: NSPoint) {
    if let storage = self.textStorage {
        let s = storage.string
        let startIndex = s.startIndex

        var padding:CGFloat = 0
        for glyphIndex in glyphsToShow.location ..< glyphsToShow.location + glyphsToShow.length {
            let characterIndex = self.characterIndexForGlyphAtIndex(glyphIndex)
            if characterIndex < s.characters.count
            {
                var glyphStr = ""
                let ch = s[startIndex.advancedBy(characterIndex)]
                switch ch {
                case " ": //Blank Space
                    glyphStr = periodCenteredUniCodeStr
                case "\n": //New Line
                    glyphStr = lineBreakUniCodeStr
                case newLineUniCodeStr:
                    glyphStr = lineBreakUniCodeStr
                    padding += 5
                default:
                    break
                }
                var glyphPoint = self.locationForGlyphAtIndex(glyphIndex)
                let glyphRect = self.lineFragmentRectForGlyphAtIndex(glyphIndex, effectiveRange: nil)
                if glyphStr.characters.count > 0{
                    glyphPoint.x = glyphPoint.x + glyphRect.origin.x
                    glyphPoint.y = glyphRect.origin.y
                    NSString(string: glyphStr).drawInRect(NSMakeRect(glyphPoint.x, glyphPoint.y, 10, 10), withAttributes: nil)
                }
            }else{
                print("Wrong count here")
            }
        }

    }
    super.drawGlyphsForGlyphRange(glyphsToShow, atPoint: origin)
}
person Shiva Kumar    schedule 21.09.2016
comment
К сожалению, этот способ слишком медленный и не работает с многостраничным макетом. - person Vitalii Vashchenko; 03.10.2016
comment
@ВиталийВащенко да, я недавно это заметил. Вы знаете лучшую идею? Так что это будет полезно для меня и других. - person Shiva Kumar; 04.10.2016
comment
Да, это чрезвычайно эффективно. Когда я нашел решение, я разместил код в своей теме вопроса здесь: do" title="nslayoutmanager скрывает символы новой строки независимо от того, что я делаю"> stackoverflow.com/questions/39545718/ - person Vitalii Vashchenko; 04.10.2016
comment
Но ваш код может быть очень легко адаптирован к многостраничному макету. Просто получите textContainer по characterIndex, и вы получите правильный объект текстового представления. Затем просто добавьте подслои CATextLayer с управляющими символами в текстовое представление. В этом случае текстовое представление должно иметь многоуровневую поддержку. Но это действительно дает хорошую производительность. Но вы должны вручную удалить эти подслои, когда менеджер компоновки делает макет недействительным, и проверить наличие дубликатов перед добавлением подслоя. - person Vitalii Vashchenko; 04.10.2016
comment
@VitaliyVashchenko ваш код намного лучше моего с точки зрения производительности (setGlyphs()), но он в Swift3, можете ли вы преобразовать его в swift 2.3? Основная проблема для меня в том, что в Swift 2.3 MemoryLayout недоступен. - person Shiva Kumar; 06.10.2016
comment
Извините, Xcode 8 не может конвертировать из 3 в 2.3 :(. Но вместо MemoryLayout попробуйте sizeOf: let glyphsRef = UnsafeMutablePointer‹CGGlyph›(malloc(sizeof(CGGlyph.self) * count)) - person Vitalii Vashchenko; 06.10.2016