首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >支持NSAttributedString属性的表情符号(kerning/段落样式)

支持NSAttributedString属性的表情符号(kerning/段落样式)
EN

Stack Overflow用户
提问于 2018-03-30 14:52:28
回答 1查看 820关注 0票数 5

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

有时有些表情符号没有显示出来。

如果我注释掉了kerning,而应用了一些段落样式,我就会得到同样的错误呈现。

我在文档中找不到任何东西,解释地拒绝了对特殊unicode字符的支持。我是做错什么了还是iOS错误?

再现bug的代码可以在这里作为游乐场使用:https://github.com/Bootstragram/Playgrounds/tree/master/LabelWithEmoji.playground

并在此复制:

代码语言:javascript
复制
//: 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()

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-03 01:23:43

TL,DR:

String.count != NSString.length。当您看到NSRange时,必须将您的String转换为UTF-16:

代码语言:javascript
复制
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
}

较长的解释

在Swift的String和ObjC的NSString之间转换是一个常见的问题。String的长度是扩展的图形素簇的数量;在ObjC中,是编码该字符串所需的UTF-16个代码点的数量。

以拇指向上字符为例:

代码语言:javascript
复制
let str = ""
let nsStr = str as NSString

print(str.count)    // 1
print(nsStr.length) // 2

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

代码语言:javascript
复制
let str = ""
let nsStr = str as NSString

print(str.count)    // 1
print(nsStr.length) // 4    

尽管这篇文章早在2003年就已经写好了,但今天它仍然是一个很好的读物:每个软件开发人员绝对、积极地了解Unicode和字符集的绝对最小值

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49576593

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档