2013-03-05 9 views
8

私は現在、複数行のテキストを表示するのにUILabelを使用しています。改行のほとんどはNSLineBreakByWordWrappingに設定されているので、ラベルは自動的に改行を挿入します。これらの改行がどこにあるかをどのように検出できますか?基本的に、私は各\nブレークを含む文字列を返したいと思います。ここでUILabelは改行を検出します

+2

+1良い質問 –

答えて

3

あなたがします私の仕事は、あなただけのをgetLinebreaksWithString に必要なパラメータを設定する必要がどのように

NSString *labelText = @"We are what our thoughts have made us; so take care about what you think. Words are secondary. Thoughts live; they travel far."; 

NSString *stringWithLineBreakChar = [self getLinebreaksWithString:labelText forWidth:200 forPoint:CGPointMake(15, 15)]; 
NSLog(@"\n\n%@",stringWithLineBreakChar); 

を使用するUILabel

- (int)getLengthForString:(NSString *)str fromFrame:(CGRect)frame withFont:(UIFont *)font 
{ 
    int length = 1; 
    int lastSpace = 1; 
    NSString *cutText = [str substringToIndex:length]; 
    CGSize textSize = [cutText sizeWithFont:font constrainedToSize:CGSizeMake(frame.size.width, frame.size.height + 500)]; 
    while (textSize.height <= frame.size.height) 
    { 
     NSRange range = NSMakeRange (length, 1); 
     if ([[str substringWithRange:range] isEqualToString:@" "]) 
     { 
      lastSpace = length; 
     } 
     length++; 
     cutText = [str substringToIndex:length]; 
     textSize = [cutText sizeWithFont:font constrainedToSize:CGSizeMake(frame.size.width, frame.size.height + 500)]; 
    } 
    return lastSpace; 
} 


-(NSString*) getLinebreaksWithString:(NSString*)labelText forWidth:(CGFloat)lblWidth forPoint:(CGPoint)point 
{ 
    //Create Label 
    UILabel *label = [[UILabel alloc] init]; 
    label.text = labelText; 
    label.numberOfLines = 0; 
    label.lineBreakMode = NSLineBreakByWordWrapping; 

    //Set frame according to string 
    CGSize size = [label.text sizeWithFont:label.font 
         constrainedToSize:CGSizeMake(lblWidth, MAXFLOAT) 
          lineBreakMode:UILineBreakModeWordWrap]; 
    [label setFrame:CGRectMake(point.x , point.y , size.width , size.height)]; 

    //Add Label in current view 
    [self.view addSubview:label]; 

    //Count the total number of lines for the Label which has NSLineBreakByWordWrapping line break mode 
    int numLines = (int)(label.frame.size.height/label.font.leading); 

    //Getting and dumping lines from text set on the Label 
    NSMutableArray *allLines = [[NSMutableArray alloc] init]; 

    BOOL shouldLoop = YES; 
    while (shouldLoop) 
    { 
     //Getting length of the string from rect with font 
     int length = [self getLengthForString:labelText fromFrame:CGRectMake(point.x, point.y, size.width, size.height/numLines) withFont:label.font] + 1;   

     [allLines addObject:[labelText substringToIndex:length]]; 

     labelText = [labelText substringFromIndex:length]; 
     if(labelText.length<length) 
      shouldLoop = NO; 
    } 

    [allLines addObject:labelText]; 
    //NSLog(@"\n\n%@\n",allLines); 

    return [allLines componentsJoinedByString:@"\n"]; 
} 

内の改行を検出するための周りで、それぞれの "\ n"ブレークを含む文字列を取得します。ここで

アウトプット Result of NSLog and Simulator

+0

これは機能しました。 キャッチされていない例外 'NSRangeException'、理由: ' - [__ NSCFString substringWithRange:]によってアプリケーションを終了している "返されています" :範囲外のインデックスまたは範囲 " – morcutt

+0

エラーの原因となるサンプル文字列をポストするだけですか?私は理解することができます –

+0

@Bhargai私は昨日それをRSSフィードでテストし、まだ同じエラーを再現する必要があります。それが起こる次回は、私はそれを投稿します。私はあなたの助けに感謝します! – morcutt

0

は、この問題に対する私の解決策です。
提供された文字列内のすべての空白文字を繰り返し、部分文字列(最初の空白から現在の空白まで)をmyラベルに設定し、高さの違いを確認します。高さが変わると、私は改行文字を挿入します(改行をシミュレートします)。

func wordWrapFormattedStringFor(string: String) -> String { 
    // Save label state 
    let labelHidden = label.isHidden 
    let labelText = label.text 

    // Set text to current label and size it to fit the content 
    label.isHidden = true 
    label.text = string 
    label.sizeToFit() 
    label.layoutIfNeeded() 

    // Prepare array with indexes of all whitespace characters 
    let whitespaceIndexes: [String.Index] = { 
     let whitespacesSet = CharacterSet.whitespacesAndNewlines 
     var indexes: [String.Index] = [] 

     string.unicodeScalars.enumerated().forEach { i, unicodeScalar in 
      if whitespacesSet.contains(unicodeScalar) { 
       let index = string.index(string.startIndex, offsetBy: i) 
       indexes.append(index) 
      } 
     } 

     // We want also the index after the last character so that when we make substrings later we include also the last word 
     // This index can only be used for substring to this index (not from or including, since it points to \0) 
     let index = string.index(string.startIndex, offsetBy: string.characters.count) 
     indexes.append(index) 

     return indexes 
    }() 

    var reformattedString = "" 

    let boundingSize = CGSize(width: label.bounds.width, height: CGFloat.greatestFiniteMagnitude) 
    let attributes = [NSFontAttributeName: font] 

    var runningHeight: CGFloat? 
    var previousIndex: String.Index? 

    whitespaceIndexes.forEach { index in 
     let string = string.substring(to: index) 
     let stringHeight = string.boundingRect(with: boundingSize, options: .usesLineFragmentOrigin, attributes: attributes, context: nil).height 

     var newString: String = { 
      if let previousIndex = previousIndex { 
       return string.substring(from: previousIndex) 
      } else { 
       return string 
      } 
     }() 

     if runningHeight == nil { 
      runningHeight = stringHeight 
     } 

     if runningHeight! < stringHeight { 
      // Check that we can create a new index with offset of 1 and that newString does not contain only a whitespace (for example if there are multiple consecutive whitespaces) 
      if newString.characters.count > 1 { 
       let splitIndex = newString.index(newString.startIndex, offsetBy: 1) 
       // Insert a new line between the whitespace and rest of the string 
       newString.insert("\n", at: splitIndex) 
      } 
     } 

     reformattedString += newString 

     runningHeight = stringHeight 
     previousIndex = index 
    } 

    // Restore label 
    label.text = labelText 
    label.isHidden = labelHidden 

    return reformattedString 
} 

Image - Comparison of output string with label text.

このソリューションは、それが役に立てば幸い、私の場合は本当によく働きました。

関連する問題