【问题标题】:is there a better way to align this column of numbers in a Swift textView?有没有更好的方法来对齐 Swift textView 中的这一列数字?
【发布时间】:2017-02-10 02:27:53
【问题描述】:

我需要格式化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? 而变得复杂

我怀疑可能有更简单的方法来实现相同的结果,并欢迎对以下 Swift 代码进行任何改进,这可能会使需要维护它的人的生活更轻松。该代码是从我的项目中提取的,并已在 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()

【问题讨论】:

  • Greg,你想像上面一样对齐你的文本吗?看起来像表格格式?
  • 是的。类似于 Word 或 Excel,除了数字需要在小数点或正斜杠列上对齐以符合 Scala 中使用的比例标准(请参阅huygens-fokker.org/microtonality/scales.html)
  • 你所有的十进制数字都必须像上图一样对齐?即所有“。”必须排队。
  • 是的。还有所有的“/”

标签: arrays swift char textview


【解决方案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) 来获得一个不错的值。但也许你可以简单地接受这样的常量。

【讨论】:

  • Andreas,你让它看起来比我的原始代码简单得多。谢谢。我现在正在尝试让它在 ViewController 的 Xcode 项目中工作,其中 tv 将出现在 StackViewController 中。 Swift 对我来说仍然是新的,所以我需要更多时间来彻底检查这个答案。请放心,一旦我有信心接受它,我会尽快回复您。
  • 安德烈亚斯,你是一颗宝石!您的解决方案将我的代码简化为现在可以在我的 Xcode 项目中使用的单个函数。这必须是公认的答案。
  • 安德烈亚斯,我已经更进一步了,但还不够。如果你能抽出一点时间,请看一下。 stackoverflow.com/q/42298647/2348597 谢谢。
【解决方案2】:

格雷格, 不是使用空间来设置列,而是根据您需要的列大小使用制表符 (\t) 树进行时间。 这将有助于以更少且功能强大的编码更好地管理代码。

谢谢

【讨论】:

  • Ashwin,你的意思是只使用"\t",而不是"\t" + filler? - 就像我在formattedTextArray[i].append("\t" + keyArray[i] + "\t" + filler + tuningArray[i] + "\n")
  • 是的,您可以使用唯一的 \t 来管理它。但单 \t 无济于事。您必须根据最大文本长度添加多个选项卡。
猜你喜欢
  • 2011-10-23
  • 1970-01-01
  • 2013-11-09
  • 1970-01-01
  • 2011-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多