2017-02-10 40 views
0

我需要通过显示分数和小数的一列,对准他们,所以小数点或正斜杠字符出现在像这样同一列的textView格式化数字的列...有没有更好的方法来对齐Swift textView中的这一列数字?

x  1/1 
    1  76.04900 
    x 193.15686 
    x 310.26471 
    4  5/4 
    x 503.42157 
    6 579.47057 
    x 696.57843 
    x  25/16 
    9 889.73529 
    x 1006.84314 
    11 1082.89214 

这在Swift中通过插入适当数量的前导空白字符并使用左对齐与列宽相同的字体来实现。

要计算空格的数量,其余字符或被除数中的字符将从每个数字中的字符总数中排除。这个简单的任务涉及减去.count.index(of:),被一个事实,即.index(of:)返回一个可选Array.Index?不是Int?

我怀疑有可能达到同样的结果更简单的方法,并欢迎雨燕下面的代码任何改进复杂这可能会让维持它的人更容易。代码是从我的项目中提取的,并已在Playground中进行了测试。

注意。 textMessage是单个字符串。它当前显示在调试区域中。它最终将显示在textView中。

//: Playground 

    import UIKit 

    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"] 

    var characterCountArray = [Int]() 
    var scaleSize    = Int() 
    var textMessage   = String() 



    func formatTextMessage() { 
    var formattedTextArray  = [String](repeating: "", count: scaleSize) 

    for i in 0..<scaleSize { 
     let element   = tuningArray[i] 
     countNumericCharactersBeforeDotOrSlash (s: element) 
     } 

    let largestStringSize  = characterCountArray.reduce(Int.min, { max($0, $1) }) 

    for i in 0..<scaleSize { 

     let thisStringSize  = characterCountArray[i] 
     let blanks    = largestStringSize - thisStringSize 
     let filler    = insertWhiteSpace(count: blanks) 

     formattedTextArray[i].append("\t" + keyArray[i] + "\t" + filler + tuningArray[i] + "\n") 
     textMessage   += formattedTextArray[i] 
     } 
    print(textMessage) 
    } 



    func insertWhiteSpace(count: Int) -> String { 
    var filler     = "" 
     for _ in 0..<count { 
     filler     = filler + " " 
     } 
    return filler 
    } 



    func countNumericCharactersBeforeDotOrSlash (s: String) { 

    let fractionalNumber  = findFractionalNumber(s: s) 
    let decimalNumber   = findDecimalNumber(s: s) 
    var thisStringSize   = 0 

    if !fractionalNumber && !decimalNumber { 
     print("Error: invalid number format") 
    } 

    if fractionalNumber  == true { 

    let pitchStringArray  = Array(s.characters) 
    let endIndex    = pitchStringArray.count 

    if let slashIndex   = pitchStringArray.index(of: "/") { 
     let dividendFiller  = endIndex - slashIndex 
     thisStringSize   = s.characters.count - dividendFiller 
    } 

    } else { 

    if decimalNumber   == true { 

     let pitchStringArray = Array(s.characters) 
     let endIndex   = pitchStringArray.count 

     if let dotIndex  = pitchStringArray.index(of: ".") { 
      let remainderFiller = endIndex - dotIndex 
      thisStringSize  = s.characters.count - remainderFiller 
      } 
     } 
     } 
    characterCountArray.append(thisStringSize) 
    } 



    func findDecimalNumber(s: String?) -> Bool { 
    if (s?.contains("."))  == true { 
     return true 
     } 
     return false 
    } 



    func findFractionalNumber(s: String?) -> Bool { 
    if (s?.contains("/"))  == true { 
     return true 
     } 
     return false 
    } 



    scaleSize     = tuningArray.count 
    formatTextMessage() 
+0

Greg,你想对齐上面的文字吗?看起来像表格合成? –

+0

是的。与Word或Excel类似,但数字需要在小数或正斜杠列上对齐以符合Scala中使用的比例标准(请参见http://www.huygens-fokker.org/microtonality/scales.html) – Greg

+0

All your十进制数字必须像上图一样对齐?即全部“。”。必须符合。 –

回答

1

你可以使用属性文本自定义制表位,就像这个例子:

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 decimalTerminators:CharacterSet = [".", "/"] 
let decimalTabOptions = [NSTabColumnTerminatorsAttributeName:decimalTerminators] 
let decimalTabLocation = CGFloat(100) // TODO: Calculate... 
var decimalTab = NSTextTab(textAlignment: .natural, location: decimalTabLocation, options: decimalTabOptions) 
var leftTab = NSTextTab(textAlignment: .left, location: CGFloat(0.01), options: [:]) 
paragraphStyle.tabStops = [leftTab, decimalTab] 

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

let tv = UITextView(frame:CGRect(x:0, y:0, width:400, height:200)) 
tv.attributedText = a 
PlaygroundPage.current.liveView = tv 

唯一的缺点是,你必须以某种方式计算小数点选项卡的位置;在这个例子中,我只是使用CGFloat(100)来获得一个很好的价值。但也许你可以简单地生活在这样一个常数。

Screenshot

+0

Andreas,你让这看起来比我原来的代码简单得多。谢谢。我现在试图让它在ViewController中的Xcode项目中工作,其中电视将出现在StackViewController中。斯威夫特对我来说仍然是新的,所以我需要更多时间彻底检查这个答案。请放心,一旦我有信心接受它,我会尽快回复您。 – Greg

+0

安德烈亚斯,你是一颗宝石!您的解决方案将我的代码减少到现在可在我的Xcode项目中工作的单个函数。这必须是被接受的答案。 – Greg

+0

安德烈亚斯,我已经采取了进一步,但它不是那里。如果你能抽出一点时间,请看看。 http://stackoverflow.com/q/42298647/2348597谢谢。 – Greg

1

格雷格, 而不是使用的空间来设置的列使用制表符(\ t)的树次基于列的大小,你需要。 这将有助于以更少和更强大的编码更好地管理代码。

感谢

+0

Ashwin,你的意思是只使用'“\ t”'而不是'“\ t”+ filler'? - 就像我在'formattedTextArray [i] .append(“\ t”+ keyArray [i] +“\ t”+ filler + tuningArray [i] +“\ n”)' – Greg

+0

是的,您可以使用只有\ t。但单一\ t不会帮助。您必须根据最大文本长度添加多个选项卡。 –

相关问题