in Swift how do I interleave NSMutableParagraphStyle() and NSMutableAttributedString to format a string to be displayed in UITextView?

梦想的初衷 提交于 2019-12-22 10:07:05

问题


In response to an example I posted previously, Andreas Oetjen showed a neat way to display a table of fractional and decimal numbers in textView using attributed strings aligning numbers so the decimal point or forward slash characters appear in the same column as shown in Example 1 below. With that introduction to attributed strings I was prompted to ask: how to display each column in a different colour or font ? (to associate data with file types found elsewhere in the app)

When I try to do this the closest I get is the display shown in Example 2 below and I can’t figure out why the text is not displayed in two columns, one in blue, the other in red with numbers in the red column aligned the same as in Example 1. Example 2 has two issues. Firstly, paragraph formatting of Example 1 is lost when font formatting is introduced and secondly, there are two versions of the text, one in colour, the other in black. I suspect both issues have the same underlying cause.

Based on Andreas' answer, the first code example below assembles strings that make up each line and then uses NSMutableParagraphStyle()to create the layout shown in Example 1 (above). The second code example applies formatting to the strings before appending formatted strings in each line - my attempt to interleave NSMutableParagraphStyle()and NSMutableAttributedString - to create the layout shown in Example 2 (above). Both were tested in Playground. With the second example, I tried switching the order of calling the formatting functions e.g.

    appendLeftColumnParagraph(textIn: column1)
    appendLeftColumnFont(i: i)

and

    appendRightColumnParagraph(textIn: column2)
    appendRightColumnFont(i: i)

instead of

    appendLeftColumnFont(i: i)
    appendLeftColumnParagraph(textIn: column1)

and

    appendRightColumnFont(i: i)
    appendRightColumnParagraph(textIn: column2)

but this only makes the coloured characters appear after the black characters instead of before. It's almost as if I can only expect to append an attributed string using either NSMutableAttributedString or NSMutableParagraphStyle() but not both. Either that or there's something basic I am not understanding about appending attributed strings.

So, assuming this is the right question, how do I interleave NSMutableParagraphStyle()and NSMutableAttributedString to format a string displayed in UITextView as two columns, one in blue, the other in red with numbers in the red column aligned the same as in Example 1 ?

I’d be grateful if someone with some fresh brain cells can help me answer this. Thanks.

Code example 1 - with NSMutableParagraphStyle() only

import UIKit
import PlaygroundSupport

var tuningArray                     = ["1/1", "76.04900", "193.15686", "310.26471", "5/4", "503.42157", "579.47057", "696.57843", "25/16", "889.73529", "1006.84314", "1082.89214"]

var keyArray                        = ["x", "1", "x", "x", "4", "x", "6", "x", "x", "9", "x", "11"]
let scaleSize                       = tuningArray.count
var textMessage                     = ""

for i in 0..<scaleSize {
    var textLine                    = "\t" + keyArray[i] + "\t" + tuningArray[i] + "\n"
    textMessage                     += textLine
}

let paragraphStyle                  = NSMutableParagraphStyle()

let leftTabLocation                 = CGFloat(50)
let rightTabLocation                = CGFloat(185)

var leftTab                         = NSTextTab(textAlignment: .left, location: leftTabLocation, options: [:])

let rightTerminators:CharacterSet   = [".", "/"]
let rightTabOptions                 = [NSTabColumnTerminatorsAttributeName:rightTerminators]
var rightTab                        = NSTextTab(textAlignment: .natural, location: rightTabLocation, options:rightTabOptions)

paragraphStyle.tabStops             = [leftTab, rightTab]

var attributedText                  = NSAttributedString(string:textMessage,attributes: [NSParagraphStyleAttributeName: paragraphStyle])

let formattedText                   = UITextView(frame:CGRect(x:0, y:0, width:300, height:200))
formattedText.attributedText        = attributedText

PlaygroundPage.current.liveView     = formattedText

Code example 2 - NSMutableParagraphStyle() with NSMutableAttributedString.init(string: )

import UIKit
import PlaygroundSupport

var tuningArray                         = ["1/1", "76.04900", "193.15686", "310.26471", "5/4", "503.42157", "579.47057", "696.57843", "25/16", "889.73529", "1006.84314", "1082.89214"]

var keyArray                            = ["x", "1", "x", "x", "4", "x", "6", "x", "x", "9", "x", "11"]

let scaleSize                           = tuningArray.count
var textMessage                         = ""

var textString                          = String()
var formattedString                     = NSAttributedString()

var rangeOfKeyString                    = NSRange()
var attributeKey                        = NSMutableAttributedString()
var rangeOfTuningString                 = NSRange()
var attributeTuning                     = NSMutableAttributedString()

let attributedTextMessage               = NSMutableAttributedString()


func appendLeftColumnParagraph(textIn: String) {
    let paragraphStyle                  = NSMutableParagraphStyle()        
    let leftTabLocation                 = CGFloat(50.0)
    let leftTab                         = NSTextTab(textAlignment: .left, location: leftTabLocation, options: [:])
    paragraphStyle.tabStops             = [leftTab]
    let attributedLeftColumnParagraph   = NSAttributedString(string:textIn, attributes: [NSParagraphStyleAttributeName: paragraphStyle])
    attributedTextMessage.append(attributedLeftColumnParagraph)
}

func appendRightColumnParagraph(textIn: String) {
    let paragraphStyle                  = NSMutableParagraphStyle()
    let rightTabLocation                = CGFloat(185.0)
    let rightSeparators:CharacterSet    = [".", "/"]
    let rightTabOptions                 = [NSTabColumnTerminatorsAttributeName: rightSeparators]
    let rightTab                        = NSTextTab(textAlignment: .natural, location: rightTabLocation, options: rightTabOptions)
    paragraphStyle.tabStops             = [rightTab]
    let attributedRightColumnParagraph  = NSAttributedString(string:textIn, attributes: [NSParagraphStyleAttributeName: paragraphStyle])
    attributedTextMessage.append(attributedRightColumnParagraph)
}

func appendLeftColumnFont(i: Int){
    rangeOfKeyString                    = (keyArray[i] as NSString).range(of: keyArray[i])
    attributeKey                        = NSMutableAttributedString.init(string: keyArray[i])
    attributeKey.addAttribute(NSForegroundColorAttributeName, value: UIColor.blue, range: rangeOfKeyString)
    attributedTextMessage.append(attributeKey)
}

func appendRightColumnFont(i: Int){
    rangeOfTuningString                 = (tuningArray[i] as NSString).range(of: tuningArray[i])
    attributeTuning                     = NSMutableAttributedString.init(string: tuningArray[i])
    attributeTuning.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: rangeOfTuningString)
    attributedTextMessage.append(attributeTuning)
}

func appendTab(){
    let attributedTab                   = NSMutableAttributedString.init(string: "\t")
    attributedTextMessage.append(attributedTab)
}

func appendNewLine(){
    let attributedNewLine               = NSMutableAttributedString.init(string: "\n")
    attributedTextMessage.append(attributedNewLine)
}


for i in 0..<scaleSize {

//    var textLine                        = "\t" + keyArray[i] + "\t" + tuningArray[i] + "\n"

    let column1                         = keyArray[i]
    let column2                         = tuningArray[i]

    appendTab()
    appendLeftColumnFont(i: i)
    appendLeftColumnParagraph(textIn: column1)

    appendTab()
    appendRightColumnFont(i: i)
    appendRightColumnParagraph(textIn: column2)

    appendNewLine()

}

    formattedString                     = attributedTextMessage

let formattedText                       = UITextView(frame:CGRect(x:0, y:0, width:300, height:200))
formattedText.attributedText            = formattedString

PlaygroundPage.current.liveView         = formattedText

回答1:


You'll have to add the paragraph style to each and every attributed string that you append (e.g. also to the new line and tab characters); the easiest way would be to add the style at the very end, to the full range:

import UIKit
import PlaygroundSupport

var tuningArray                         = ["1/1", "76.04900", "193.15686", "310.26471", "5/4", "503.42157", "579.47057", "696.57843", "25/16", "889.73529", "1006.84314", "1082.89214"]

var keyArray                            = ["x", "1", "x", "x", "4", "x", "6", "x", "x", "9", "x", "11"]

let scaleSize                           = tuningArray.count
var textMessage                         = ""

var textString                          = String()
var formattedString                     = NSAttributedString()

var rangeOfKeyString                    = NSRange()
var attributeKey                        = NSMutableAttributedString()
var rangeOfTuningString                 = NSRange()
var attributeTuning                     = NSMutableAttributedString()

let attributedTextMessage               = NSMutableAttributedString()

func getParagraphStyles() -> NSMutableParagraphStyle {
    let paragraphStyle                  = NSMutableParagraphStyle()
    let leftTabLocation                 = CGFloat(50.0)
    let leftTab                         = NSTextTab(textAlignment: .left, location: leftTabLocation, options: [:])

    let rightTabLocation                = CGFloat(185.0)
    let rightSeparators:CharacterSet    = [".", "/"]
    let rightTabOptions                 = [NSTabColumnTerminatorsAttributeName: rightSeparators]
    let rightTab                        = NSTextTab(textAlignment: .natural, location: rightTabLocation, options: rightTabOptions)

    paragraphStyle.tabStops             = [leftTab, rightTab]
    return paragraphStyle
}


func appendLeftColumnFont(i: Int){
    rangeOfKeyString                    = (keyArray[i] as NSString).range(of: keyArray[i])
    attributeKey                        = NSMutableAttributedString.init(string: keyArray[i])
    attributeKey.addAttribute(NSForegroundColorAttributeName, value: UIColor.blue, range: rangeOfKeyString)
    attributedTextMessage.append(attributeKey)
}

func appendRightColumnFont(i: Int){
    rangeOfTuningString                 = (tuningArray[i] as NSString).range(of: tuningArray[i])
    attributeTuning                     = NSMutableAttributedString.init(string: tuningArray[i])
    attributeTuning.addAttribute(NSForegroundColorAttributeName, value: UIColor.red, range: rangeOfTuningString)
    attributedTextMessage.append(attributeTuning)
}

func appendTab(){
    let attributedTab                   = NSMutableAttributedString.init(string: "\t")
    attributedTextMessage.append(attributedTab)
}

func appendNewLine(){
    let attributedNewLine               = NSMutableAttributedString.init(string: "\n")
    attributedTextMessage.append(attributedNewLine)
}


for i in 0..<scaleSize {

    //    var textLine                        = "\t" + keyArray[i] + "\t" + tuningArray[i] + "\n"

    let column1                         = keyArray[i]
    let column2                         = tuningArray[i]

    appendTab()
    appendLeftColumnFont(i: i)

    appendTab()
    appendRightColumnFont(i: i)

    appendNewLine()

}

// Apply paragraph to whole string:
var paragraphStyle = getParagraphStyles()
let fullRange = NSRange(location: 0, length: attributedTextMessage.length)
attributedTextMessage.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: fullRange)

formattedString                     = attributedTextMessage


let formattedText                       = UITextView(frame:CGRect(x:0, y:0, width:300, height:200))
formattedText.attributedText            = formattedString

PlaygroundPage.current.liveView         = formattedText



来源:https://stackoverflow.com/questions/42298647/in-swift-how-do-i-interleave-nsmutableparagraphstyle-and-nsmutableattributedst

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!