2017-09-20 9 views
-4

各行に収まる文字数に基づいて文字列を配列に分割する必要があります。配列内の各オブジェクトは1行のテキストである必要があります。私は文字列内の行数を計算することができますが、私は1行に最大文字数を見つける方法を見つけることができません。文字列の中のいくつの文字が1行に収まるかを調べる

func lineCount(forText text: String) -> Int { 
     let font = UIFont.systemFont(ofSize: 24.0) 
     let width: Int = Int(self.tableView.frame.size.width) 
     let rect: CGRect = text.boundingRect(with: CGSize(width: CGFloat(width), height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil) 
     return Int(ceil(rect.size.height/font.lineHeight)) 
    } 
+0

興味があるだけ。あなたはどんな種類のキャラクターを使用するかによってそれは違うでしょうか? 10の幅が10 Aより短いと言う... iiiiiiiiii:AAAAAAAAAA – sCha

+0

はい。特定の文字列の何文字が1行に収まるかを知りたい。基本的には、行ごとに取得できる最大値に基づいて文字列を配列に分割する必要があります。最初のようなものがAAAAAなら...それはあまり適合しません。私はそれを計算することができる必要があります – user1079052

+0

私はあなたが正しいレンダリングされた長さに合うように 'String'を分割したいと思っていますか?あなたはその質問を明確にしたいかもしれません。 – ColGraff

答えて

0

一部のフォントは、可変幅の文字を持っているので、あなたは、すべてのフォントでの行の文字のセット数を取得することはできません。あなたにできることはアップライン・サイズのチャンクに文字列を分割しようとする次のとおりです。

extension String { 
    func split(width: CGFloat, font: UIFont) -> [String] { 
    guard !self.isEmpty else { return [String]() } 

    var lines = [String]() 

    // set up range of the split 
    var splitStart = self.startIndex 
    var splitEnd = self.startIndex 

    repeat { 
     // advance the end range for the split 
     splitEnd = self.index(after: splitStart) 

     // initial split to test 
     var line = String(characters[splitStart..<splitEnd]) 

     // while we're before the end test the rendered width 
     while splitEnd < self.endIndex && 
     line.size(attributes: [NSFontAttributeName: font]).width < width { 
      // add one more character 
      splitEnd = self.index(after: splitEnd) 
      line = String(characters[splitStart..<splitEnd]) 
     } 

     // add split to array and set up next split 
     lines.append(line) 
     splitStart = splitEnd 
    } while splitEnd < self.endIndex // don't go past the end of the string 


    // add remainder of string to array 
    lines.append(String(characters[splitStart..<self.endIndex])) 
    return lines 
    } 
} 

これは始まる、行数で割る、文字列全体の幅を事前に計算することにより、ビットを最適化することができ、各行の平均幅を計算し、それが収まるまで多かれ少なかれ文字を試してください。しかし、それはコードをはるかに複雑にします。

単語が分割されないようにしたい場合は、各単語の開始位置を保存し、行の終わりに達すると、単語の前に分割終了を作成します次の分割にもちろん、分割するには時間がかかりすぎる単語、ハイフネーションする単語なども考慮する必要があります。

別の方法では、より高度なレイアウトを必要とするので、使用するのだろう、それを行うにはNSLayoutManagerNSTextContainer

let text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Non est ista, inquam, Piso, magna dissensio. Minime vero istorum quidem, inquit. Graecum enim hunc versum nostis omnes-: Suavis laborum est praeteritorum memoria. Negat enim summo bono afferre incrementum diem. Quasi ego id curem, quid ille aiat aut neget. Semper enim ex eo, quod maximas partes continet latissimeque funditur, tota res appellatur. Duo Reges: constructio interrete." 

let font = UIFont.systemFont(ofSize: 24.0) 

// set up styled text for the container 
let storage = NSTextStorage(string: text, attributes: [NSFontAttributeName: font]) 

// add a layout manage for the storage 
let layout = NSLayoutManager() 
storage.addLayoutManager(layout) 

// Set up the size of the container 
// width is what we care about, height is maximum 
let width:CGFloat = 500 
let container = NSTextContainer(size: CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)) 

// add the container to the layout 
layout.addTextContainer(container) 

var lines = [String]() 

// generate the layout and add each line to the array 
layout.enumerateLineFragments(forGlyphRange: NSMakeRange(0, storage.length)) { 
    lines.append(storage.attributedSubstring(from: $0.3).string) 
} 

lines.forEach { print($0) } 

結果:あなたはまたを通じてハイフネーションおよびその他の動作を提供することができます

Lorem ipsum dolor sit amet, consectetur 
adipiscing elit. Non est ista, inquam, Piso, 
magna dissensio. Minime vero istorum 
quidem, inquit. Graecum enim hunc versum 
nostis omnes-: Suavis laborum est 
praeteritorum memoria. Negat enim summo 
bono afferre incrementum diem. Quasi ego id 
curem, quid ille aiat aut neget. Semper enim 
ex eo, quod maximas partes continet 
latissimeque funditur, tota res appellatur. Duo 
Reges: constructio interrete. 

あなたが好きなら、NSLayoutManager

+0

これはワードを分割するのではなく、次の行にワードを取ることを考慮しません。 – user1079052

+0

@ user1079052もちろん、それは単なる例です。これらの行為を追加する必要があります。あなたの質問では、あなたがそれらを必要としているとは言いません – ColGraff

+0

それは、私が適用するために単語の折り返し規則が必要であると述べていない私の間違いです。 – user1079052

-2

私は、これが最も効率的な方法があるのか​​はわからないが、私はそれがこれで動作するようになった:

func getLinesArrayOfString(forText text: String) ->NSArray { 
     let font = UIFont.systemFont(ofSize: 24.0) 
     let label = UILabel(frame: CGRect(x: 0, y: 0, width: self.tableView.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) 
     label.numberOfLines = 0 
     label.text = text as String 
     label.font = font 
     label.sizeToFit() 
     var linesArray: [Any] = [] 


     let rect: CGRect = label.frame 


     let attStr = NSMutableAttributedString(string: text) 
     attStr.addAttribute((NSAttributedStringKey(rawValue: kCTFontAttributeName as String)), value: font, range: NSRange(location: 0, length: attStr.length)) 
     let frameSetter: CTFramesetter = CTFramesetterCreateWithAttributedString(attStr) 
     let path: CGMutablePath = CGMutablePath() 
     path.addRect(CGRect(x: 0, y: 0, width: rect.size.width, height: 100000), transform: .identity) 
     let frame: CTFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 
     let lines = CTFrameGetLines(frame) as? [Any] 

     for line: Any in lines! { 
      let lineRef = line 
      let lineRange: CFRange = CTLineGetStringRange(lineRef as! CTLine) 
      let range = NSRange(location: lineRange.location, length: lineRange.length) 
      let lineString: String = (text as NSString).substring(with: range) 



      CFAttributedStringSetAttribute(attStr, lineRange, kCTKernAttributeName, font) 
      CFAttributedStringSetAttribute(attStr, lineRange, kCTKernAttributeName, font) 
      linesArray.append(lineString) 
     } 
     return linesArray as NSArray 
    } 
+0

ここには多くの不必要なコードがあり、それを行うにはかなりラウンドアバウトな方法です。私が質問に答えた方法を見ると、これを処理するより簡単な方法がわかります。 – ColGraff