代码之家  ›  专栏  ›  技术社区  ›  Mick F

表情符号支持NSAttributedString属性(紧排/段落样式)

  •  5
  • Mick F  · 技术社区  · 7 年前

    我在UILabel上使用一个紧排属性来显示带有一些自定义字母间距的文本。不幸的是,在显示用户生成的字符串时,有时会看到如下情况:

    即有时某些表情符号不显示

    如果我注释掉字距,但应用一些段落样式,则会得到同样的错误呈现

    我在文档中找不到任何明确拒绝支持特殊unicode字符的内容。我是做错了什么还是iOS错误

    复制错误的代码可在此处作为游乐场使用: https://github.com/Bootstragram/Playgrounds/tree/master/LabelWithEmoji.playground

    并抄录于此:

    用于显示用户界面的基于UIKit的游乐场 导入UIKit 导入PlaygroundSupport 扩展NSAttribute字符串{ 静态func kernedSpacedText(\uText:String, 字母间距:CGFloat=0.0, 线宽:CGFloat?=无)—>NSAttribute字符串{ //TODO添加字体属性 让attributedString=NSMutableAttributedString(字符串:文本) attributedString。addAttribute(NSAttributedStringKey.kern, 值:字母间距, 范围:NSRange(位置:0,长度:text.count)) 如果let lineHeight=lineHeight{ 让paragraphStyle=NSMutableParagraphStyle() 段落样式。行距=线宽 attributedString。addAttribute(NSAttributedStringKey.paragraphStyle, 值:段落样式, 范围:NSRange(位置:0,长度:text.count)) } 返回AttributeString } } //对于UIFont中的familyName。familyNames家族{ //用于UIFont中的fontName。fontNames(用于familyName:familyName){ //打印(fontName) //} //} 类MyViewController:UIViewController{ 重写func loadView(){ let view=UIView() 看法背景颜色=。白色 让我来告诉你 let label=UILabel() 标签框架=CGRect(x:150,y:200,宽度:200,高度:100) 标签AttributeText=NSAttribute字符串。kernedSpacedText(myString) 标签numberOfLines=0 标签text颜色=。黑色 看法添加子视图(标签) 自己视图=视图 } } //在实时视图窗口中显示视图控制器 PlaygroundPage。现在的liveView=MyViewController()

    谢谢

    /Users/mick/Desktop/Capture d’écran 2018-03-30 à 16.45.55.png

    即有时某些表情符号不显示。

    如果我注释掉字距,但应用一些段落样式,则会得到同样的错误呈现。

    我在文档中找不到任何明确拒绝支持特殊unicode字符的内容。我是做错了什么还是iOS错误?

    复制错误的代码可在此处作为游乐场使用: https://github.com/Bootstragram/Playgrounds/tree/master/LabelWithEmoji.playground

    并复制到此处:

    //: A UIKit based Playground for presenting user interface
    
    import UIKit
    import PlaygroundSupport
    
    extension NSAttributedString {
        static func kernedSpacedText(_ text: String,
                                        letterSpacing: CGFloat = 0.0,
                                        lineHeight: CGFloat? = nil) -> NSAttributedString {
            // TODO add the font attribute
    
            let attributedString = NSMutableAttributedString(string: text)
            attributedString.addAttribute(NSAttributedStringKey.kern,
                                          value: letterSpacing,
                                          range: NSRange(location: 0, length: text.count))
    
            if let lineHeight = lineHeight {
                let paragraphStyle = NSMutableParagraphStyle()
                paragraphStyle.lineSpacing = lineHeight
    
                attributedString.addAttribute(NSAttributedStringKey.paragraphStyle,
                                              value: paragraphStyle,
                                              range: NSRange(location: 0, length: text.count))
            }
    
            return attributedString
        }
    }
    
    //for familyName in UIFont.familyNames {
    //    for fontName in UIFont.fontNames(forFamilyName: familyName) {
    //        print(fontName)
    //    }
    //}
    
    class MyViewController : UIViewController {
        override func loadView() {
            let view = UIView()
            view.backgroundColor = .white
    
            let myString = "1⚽📺🍻⚾️🌯🏄‍♂️👍\n2 😀💿💸 🍻"
    
            let label = UILabel()
            label.frame = CGRect(x: 150, y: 200, width: 200, height: 100)
            label.attributedText = NSAttributedString.kernedSpacedText(myString)
            label.numberOfLines = 0
            label.textColor = .black
    
            view.addSubview(label)
            self.view = view
        }
    }
    // Present the view controller in the Live View window
    PlaygroundPage.current.liveView = MyViewController()
    

    谢谢

    1 回复  |  直到 7 年前
        1
  •  8
  •   Code Different    7 年前

    TL、DR:

    String.count != NSString.length 。任何时候你看到 NSRange ,您必须转换 String 进入UTF-16:

    static func kernedSpacedText(_ text: String,
                                    letterSpacing: CGFloat = 0.0,
                                    lineHeight: CGFloat? = nil) -> NSAttributedString {
        // TODO add the font attribute
    
        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(NSAttributedStringKey.kern,
                                      value: letterSpacing,
                                      range: NSRange(location: 0, length: text.utf16.count))
    
        if let lineHeight = lineHeight {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.lineSpacing = lineHeight
    
            attributedString.addAttribute(NSAttributedStringKey.paragraphStyle,
                                          value: paragraphStyle,
                                          range: NSRange(location: 0, length: text.utf16.count))
        }
    
        return attributedString
    }
    

    更长的解释

    你的是一个常见的问题 一串 和ObjC的 NSString 。a的长度 一串 是的编号 扩展的grapheme簇 ;在ObjC中,它是对该字符串进行编码所需的UTF-16代码点的数量。

    以拇指向上字符为例:

    let str = "👍"
    let nsStr = str as NSString
    
    print(str.count)    // 1
    print(nsStr.length) // 2
    

    当涉及到国旗表情时,事情会变得更加奇怪:

    let str = "🇺🇸"
    let nsStr = str as NSString
    
    print(str.count)    // 1
    print(nsStr.length) // 4    
    

    尽管这篇文章写于2003年,但时至今日,它仍然是一本很好的读物: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets