在swift for iOS中用普通(Android格式)文本创建一个属性字符串

Sok*_*oko 7 xcode nsattributedstring ios nsmutableattributedstring swift

我正在从Localizable.strings中读取字符串,其中包含类似于Android应用程序的strings.xml中的内容.

"testShort" = "A <b>short</b>\ntest with another<b>bold text</b>";
Run Code Online (Sandbox Code Playgroud)

粗体和换行是我文本中唯一的两个格式属性.我试图开发这样的方法几天没有成功:

func ConvertText(inputText: String) -> NSAttributedString {
    // here comes the conversion to a representation with Helvetica 14pt and Helvetica-Bold 14pt including line feeds.
}
Run Code Online (Sandbox Code Playgroud)

我的最终目标是在UITextView的attributedText中显示文本.

在不知道Objective-C的情况下成为Swift和iOS的新手我发现很难做String操作,因为它们非常不同且复杂,所有示例都在Objective-C中.更令人困难的是,大多数API方法在Swift中不可用或与Objective-C不同......

这是我到目前为止尝试的方法体,这里有很多其他帖子:

var test = inputText.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!
attrStr = NSAttributedString(
        data: test,
        options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
        documentAttributes: nil,
        error: nil)!
return attrStr
Run Code Online (Sandbox Code Playgroud)

这里的主要问题\n是没有转换,字体非常小而且不同.

接下来,我尝试手动加粗文本的一部分.它看起来像那样:

var newText = NSMutableAttributedString(string: inputText)
newText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 14.0)!, range: NSRange(location:2,length:4))
Run Code Online (Sandbox Code Playgroud)

现在我尝试在文本中搜索属性,删除它们并使用类似的addAttribute

// Start of bold text
var range = newText.rangeOfString("<b>")!
// End of bold text
var range2 = newText.rangeOfString("</b>")!

// replacing attributes
newText = newText.stringByReplacingCharactersInRange(range, withString: "")
newText = newText.stringByReplacingCharactersInRange(range2, withString: "")

// creating a range for bold => error "'String.Index' is not convertible to 'int'"
// how to do such a thing
var boldRange = NSMakeRange(range.startIndex, range2.endIndex -3)

// setting bold
newText.addAttribute(NSFontAttributeName, value: UIFont(name: "Helvetica-Bold", size: 14.0)!, range: boldRange)
Run Code Online (Sandbox Code Playgroud)

这整个范围是我目前的主要问题,因为它与字符串中的简单位置完全不同.

这个问题是缺少(或隐藏)文档的一个很好的例子:

addAttribute希望的NSRange时,rangeOfString似乎根据的错误消息我去提供一个通用的范围-但它没有资料.Xcode on中的Search Documentation按钮rangeOfString()指向NSString.在那里搜索rangeOfString()说它返回NSRange.点击导致一个类型别名的信息_NSRange这反过来有两个名为NSUInteger性质locationlength.我在XCode中看到的startIndex和endIndex属性在哪里?很混乱...

如果你可以给我一些片段或提示,我在这里错了,或者甚至是方法体,那将是很好的,因为我仍然希望如果你对iOS和Swift很了解它并不太难.我的目标是支持iOS 7.1,但如果使用iOS 8更容易,那么它也很好.

Mar*_*n R 8

关于你的第一种方法NSAttributedString:

这给出了(现在为Swift 2更新):

func convertText(inputText: String) -> NSAttributedString {

    var html = inputText

    // Replace newline character by HTML line break
    while let range = html.rangeOfString("\n") {
        html.replaceRange(range, with: "<br />")
    }

    // Embed in a <span> for font attributes:
    html = "<span style=\"font-family: Helvetica; font-size:14pt;\">" + html + "</span>"

    let data = html.dataUsingEncoding(NSUnicodeStringEncoding, allowLossyConversion: true)!
    let attrStr = try? NSAttributedString(
        data: data,
        options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],
        documentAttributes: nil)
    return attrStr!
}
Run Code Online (Sandbox Code Playgroud)

关于你的第二种方法:

有两种不同的rangeOfString()方法,一种用于(Swift)String,一种用于(基础)NSString.该String方法返回一个Range<String.Index> 并且该NSString方法返回一个NSRange.

在这两者之间转换是可能的但复杂的.原因是在String每个"扩展字形簇"中计为一个字符,而在 NSString每个UTF-16单元中计数.扩展的字形簇可以是一个或多个UTF-16单元(""是两个UTF-16单元,""是四个).

addAttribute()方法只接受一个NSRange.要解决这个问题,最简单的方法是将斯威夫特串转换NSString,并与工作NSRange 而已.然后你的方法可能如下所示:

func convertText(inputText: String) -> NSAttributedString {

    let attrString = NSMutableAttributedString(string: inputText)
    let boldFont = UIFont(name: "Helvetica-Bold", size: 14.0)!

    var r1 = (attrString.string as NSString).rangeOfString("<b>")
    while r1.location != NSNotFound {
        let r2 = (attrString.string as NSString).rangeOfString("</b>")
        if r2.location != NSNotFound  && r2.location > r1.location {
            let r3 = NSMakeRange(r1.location + r1.length, r2.location - r1.location - r1.length)
            attrString.addAttribute(NSFontAttributeName, value: boldFont, range: r3)
            attrString.replaceCharactersInRange(r2, withString: "")
            attrString.replaceCharactersInRange(r1, withString: "")
        } else {
            break
        }
        r1 = (attrString.string as NSString).rangeOfString("<b>")
    }

    return attrString
}
Run Code Online (Sandbox Code Playgroud)