【问题标题】:drawGlyphsForGlyphRange in Swift (Displaying Invisible characters). replaceGlyphAtIndex deprecatedSwift 中的 drawGlyphsForGlyphRange(显示不可见字符)。 replaceGlyphAtIndex 已弃用
【发布时间】:2016-09-14 11:08:50
【问题描述】:

我正在尝试使用下面的类 & func 来显示不可见字符,它工作正常。

但在 OS X 10.11 中不推荐使用 replaceGlyphAtIndex,我们需要使用 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)
}

}

【问题讨论】:

    标签: swift xcode macos cocoa nslayoutmanager


    【解决方案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)
    }
    

    【讨论】:

    • 很遗憾,这种方式太慢了,不适合多页布局
    • @VitaliyVashchenko 是的,我最近确实注意到了这一点。你知道更好的主意吗?以便他对我和其他人有所帮助。
    • 是的,它非常高效。当我找到解决方案时,我在我的问题主题中发布了代码:stackoverflow.com/questions/39545718/…
    • 但是你的代码很容易被多页布局采用。只需通过 characterIndex 获取 textContainer,您将获得正确的文本视图对象。然后只需将带有控制字符的 CATextLayer 子图层添加到您的文本视图中。在这种情况下,您的文本视图应该是图层支持的。但它也确实得到了很好的表现。但是,当布局管理器使布局无效时,您应该手动删除这些子层,并在添加子层之前检查重复项。
    • @VitaliyVashchenko 你的代码在性能方面比我的好很多(setGlyphs()),但它是在 Swift3 中,你能把它转换成 swift 2.3 吗?对我来说主要问题是在 Swift 2.3 中“MemoryLayout”不可用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-06
    • 1970-01-01
    • 2020-12-14
    • 2010-09-26
    • 2012-03-03
    • 2014-12-31
    • 1970-01-01
    相关资源
    最近更新 更多