2013-03-05 16 views
8

Attualmente sto utilizzando uno UILabel per visualizzare più righe di testo. L'interruzione di riga è impostata su NSLineBreakByWordWrapping in modo che l'etichetta inserisca automaticamente interruzioni di riga. Come posso rilevare dove sono quelle interruzioni di riga? Fondamentalmente, voglio restituire una stringa con ogni pausa \n inclusa.UILabel rileva interruzioni di riga

+2

+1 buona domanda –

risposta

3

Ecco il mio lavoro in giro per il rilevamento di interruzioni di linea all'interno 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"]; 
} 

Come utilizzare

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); 

Hai solo bisogno di impostare i parametri richiesti dalla getLinebreaksWithString e vi ottenere una stringa con ogni pausa "\ n" inclusa.

OutPut Result of NSLog and Simulator

+0

Questo ha funzionato. Anche se su alcune stringhe ho problemi con "if ([[str substringWithRange: range] isEqualToString: @" "]) " return "Termina l'app a causa dell'eccezione non rilevata" NSRangeException ", motivo:" - [__ NSCFString substringWithRange:] : Intervallo o indice fuori limite "" – morcutt

+0

È sufficiente pubblicare la stringa di esempio che causa l'errore? Posso essere in grado di capire –

+0

@Bhargai l'ho incontrato ieri testandolo con un feed RSS e devo ancora riprodurre lo stesso errore. La prossima volta che si verificherà, lo posterò. Apprezzo il vostro aiuto! – morcutt

0

Qui è la mia soluzione a questo problema.
I iterare tutti i caratteri di spaziatura nella stringa fornita, impostare sottostringhe (dall'inizio allo spazio bianco corrente) alla mia etichetta e controllare la differenza nell'altezza. Quando l'altezza cambia, inserisco un nuovo carattere di linea (simula un'interruzione di riga).

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.

Questa soluzione ha funzionato molto bene nel mio caso, spero che aiuta.

Problemi correlati