2010-12-12 22 views
12

Existe-t-il un moyen facile d'obtenir (ou simplement afficher) le texte d'une ligne donnée dans un UILabel?Comment obtenir du texte de la nième ligne d'UILabel?

Mon UILabel affiche correctement mon texte et l'affiche joliment mais parfois je dois pouvoir afficher certaines lignes mais évidemment j'ai besoin de savoir comment UILabel a positionné tout pour faire cela. Je sais que cela pourrait facilement être fait avec une sous-chaîne, mais j'ai besoin de connaître le point de départ et d'arrivée de la ligne.

Sinon, je pourrais faire défiler le UILabel s'il y avait une sorte de décalage à l'image UILabel et cacher le reste du contenu que je ne voulais pas voir.

Je n'ai pas été en mesure de découvrir quoi que ce soit qui montre comment cela pourrait être fait facilement. Quelqu'un a-t-il de bonnes idées?

Merci

iphaaw

Répondre

4

Je ne pense pas qu'il y ait une façon native pour ce faire (comme une méthode "takethenline").
Je peux trouver une solution délicate mais je ne suis pas sûr que ce soit la meilleure.
Vous pourriez diviser votre étiquette en un tableau de mots.
Ensuite, on boucle pourrait le tableau et vérifier la hauteur du texte jusqu'à ce mot comme ceci:

NSString *texttocheck; 
float old_height = 0; 
int linenumber = 0; 

for (x=0; x<[wordarray lenght]; x++) { 
    texttocheck = [NSString stringWithFormat:@"%@ %@", texttocheck, [wordarray objectAtIndex:x]]; 

    float height = [text sizeWithFont:textLabel.font 
        constrainedToSize:CGSizeMake(textLabel.bounds.size.width,99999) 
         lineBreakMode:UILineBreakModeWordWrap].height; 

    if (old_height < height) { 
     linenumber++; 
    } 
} 

Si des changements de hauteur, cela signifie qu'il ya un saut de ligne avant le mot.
Je ne peux pas vérifier si la syntaxe est correctement écrite maintenant, donc vous devez vérifier vous-même.

0

Si tous vos caractères sont affichés dans la même taille, c'est-à-dire qu'ils sont inclus dans une boîte de taille commune, vous pouvez exploiter cela. (Cela semble être le cas avec les caractères japonais, par exemple.)

Sinon, vous pouvez interroger la taille de chaque caractère dans la police d'affichage et calculer ce que la ligne devrait être. Le seul souci est alors que votre calcul pourrait être en désaccord avec ce que fait Apple en coulisses - auquel cas, je vous recommande de passer outre le dessin du cadre de texte. Recherchez le texte principal dans les documents pour cela.

(je fais ce mal, mais je ne trouve pas la méthode d'Apple comme indiqué dans la documentation était très précis, donc je l'ai fait quelque chose d'autre moi-même.)

19

J'ai une meilleure façon de trouvé .

Vous pouvez obtenir ceci avec l'aide de CoreText.framework.

1.Ajouter CoreText.framework.
2.Import #import <CoreText/CoreText.h>.
Ensuite, utilisez la méthode ci-dessous:

- (NSArray *)getLinesArrayOfStringInLabel:(UILabel *)label { 
    NSString *text = [label text]; 
    UIFont *font = [label font]; 
    CGRect rect = [label frame]; 

    CTFontRef myFont = CTFontCreateWithName((__bridge CFStringRef)([font fontName]), [font pointSize], NULL); 
    NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text]; 
    [attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)]; 


    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)attStr); 

    CGMutablePathRef path = CGPathCreateMutable(); 
    CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000)); 

    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL); 

    NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame); 
    NSMutableArray *linesArray = [[NSMutableArray alloc]init]; 

    for (id line in lines) 
    { 
     CTLineRef lineRef = (__bridge CTLineRef)line; 
     CFRange lineRange = CTLineGetStringRange(lineRef); 
     NSRange range = NSMakeRange(lineRange.location, lineRange.length); 

     NSString *lineString = [text substringWithRange:range]; 
     [linesArray addObject:lineString]; 
    } 

    return (NSArray *)linesArray; 
} 

Appelez cette méthode: -

NSArray *linesArray = [self getLinesArrayOfStringInLabel:yourLabel]; 

Maintenant, vous pouvez utiliser linesArray.

+0

réponse impressionnante .... heads up .... sauvé beaucoup de mon temps. merci .. –

+0

fabuleux, génial. Merci beaucoup. –

5

Réponse avec la version correcte !!!!

-(NSArray *)getLinesArrayOfStringInLabel:(UILabel *)label 
{ 
    NSString *text = [label text]; 
    UIFont *font = [label font]; 
    CGRect rect = [label frame]; 

    CTFontRef myFont = CTFontCreateWithName((CFStringRef)([font fontName]), [font pointSize], NULL); 
    NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text]; 
    [attStr addAttribute:(NSString *)kCTFontAttributeName value:(id)myFont range:NSMakeRange(0, attStr.length)]; 

    CFRelease(myFont); 

    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attStr); 

    CGMutablePathRef path = CGPathCreateMutable(); 
    CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000)); 

    CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL); 

    NSArray *lines = (NSArray *)CTFrameGetLines(frame); 

    NSMutableArray *linesArray = [[NSMutableArray alloc]init]; 

    for (id line in lines) 
    { 
     CTLineRef lineRef = (CTLineRef)line; 
     CFRange lineRange = CTLineGetStringRange(lineRef); 
     NSRange range = NSMakeRange(lineRange.location, lineRange.length); 

     NSString *lineString = [text substringWithRange:range]; 

     CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithFloat:0.0])); 
     CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithInt:0.0])); 

     //NSLog(@"''''''''''''''''''%@",lineString); 
     [linesArray addObject:lineString]; 

    } 
    [attStr release]; 

    CGPathRelease(path); 
    CFRelease(frame); 
    CFRelease(frameSetter); 


    return (NSArray *)linesArray; 
} 
7

Swift 3

func getLinesArrayFromLabel(label:UILabel) -> [String] { 

     let text:NSString = label.text! as NSString // TODO: Make safe? 
     let font:UIFont = label.font 
     let rect:CGRect = label.frame 

     let myFont:CTFont = CTFontCreateWithName(font.fontName as CFString, font.pointSize, nil) 
     let attStr:NSMutableAttributedString = NSMutableAttributedString(string: text as String) 
     attStr.addAttribute(String(kCTFontAttributeName), value:myFont, range: NSMakeRange(0, attStr.length)) 
     let frameSetter:CTFramesetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString) 
     let path:CGMutablePath = CGMutablePath() 
     path.addRect(CGRect(x:0, y:0, width:rect.size.width, height:100000)) 

     let frame:CTFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 
     let lines = CTFrameGetLines(frame) as NSArray 
     var linesArray = [String]() 

     for line in lines { 
      let lineRange = CTLineGetStringRange(line as! CTLine) 
      let range:NSRange = NSMakeRange(lineRange.location, lineRange.length) 
      let lineString = text.substring(with: range) 
      linesArray.append(lineString as String) 
     } 
     return linesArray 
} 

Swift version 2 (Xcode 7) (testé, et re-dirigé à partir de la réponse Swift 1)

func getLinesArrayOfStringInLabel(label:UILabel) -> [String] { 

let text:NSString = label.text! // TODO: Make safe? 
let font:UIFont = label.font 
let rect:CGRect = label.frame 

let myFont:CTFontRef = CTFontCreateWithName(font.fontName, font.pointSize, nil) 
let attStr:NSMutableAttributedString = NSMutableAttributedString(string: text as String) 
attStr.addAttribute(String(kCTFontAttributeName), value:myFont, range: NSMakeRange(0, attStr.length)) 
let frameSetter:CTFramesetterRef = CTFramesetterCreateWithAttributedString(attStr as CFAttributedStringRef) 
let path:CGMutablePathRef = CGPathCreateMutable() 
CGPathAddRect(path, nil, CGRectMake(0, 0, rect.size.width, 100000)) 
let frame:CTFrameRef = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 
let lines = CTFrameGetLines(frame) as NSArray 
var linesArray = [String]() 

for line in lines { 
    let lineRange = CTLineGetStringRange(line as! CTLine) 
    let range:NSRange = NSMakeRange(lineRange.location, lineRange.length) 
    let lineString = text.substringWithRange(range) 
    linesArray.append(lineString as String) 
} 
return linesArray 
} 
+1

Vous devez remplacer le code suivant ** texte: NSString = label.text! // TODO: Rendre sûr? ** avec ** garde laisser le texte: NSString = self.text else { return [] } ** –

+4

Au début cela n'a pas fonctionné pour moi - le nombre de lignes calculé était plus que le nombre réel. mais alors j'ai changé la ligne avec CGPathAddRect à: CGPathAddRect (chemin, aucun, CGRectMake (0, 0, rect.size.width + 15, 100000)) et cela a fonctionné comme il a dû. – locomotion

+0

ce n'est pas fiable. voir: https://stackoverflow.com/questions/46923039/get-each-line-of-text-in-a-uilabel – chicobermuda

1

Swift 3 - Xcode 8.1

J'ai mis ensemble le code de la précédente nswers pour créer un Swift 3, compatible Xcode 8.1 extension à UILabel retournant la première ligne de l'étiquette.

import CoreText 

extension UILabel { 

    /// Returns the String displayed in the first line of the UILabel or "" if text or font is missing 
    var firstLineString: String { 

    guard let text = self.text else { return "" } 
    guard let font = self.font else { return "" } 
    let rect = self.frame 

    let attStr = NSMutableAttributedString(string: text) 
    attStr.addAttribute(String(kCTFontAttributeName), value: CTFontCreateWithName(font.fontName as CFString, font.pointSize, nil), range: NSMakeRange(0, attStr.length)) 

    let frameSetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString) 
    let path = CGMutablePath() 
    path.addRect(CGRect(x: 0, y: 0, width: rect.size.width + 7, height: 100)) 
    let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 

    guard let line = (CTFrameGetLines(frame) as! [CTLine]).first else { return "" } 
    let lineString = text[text.startIndex...text.index(text.startIndex, offsetBy: CTLineGetStringRange(line).length-2)] 

    return lineString 
    } 
} 

Pour l'utiliser, simple appel firstLineString sur votre UILabel par exemple comme ceci:

let firstLine = myLabel.firstLineString 
2

Ceci est la version Swift 3 pour obtenir toutes les lignes dans l'étiquette. (@fredpi a une réponse similaire, mais il est seulement pour la première ligne)

extension UILabel { 

    func getArrayOfLinesInLabel() -> [String] { 

     let text = NSString(string: self.text ?? "-- -- -- --") 
     let font = self.font ?? // Your default font here 
     let rect = self.frame 

     let myFont = CTFontCreateWithName(font.fontName as CFString?, font.pointSize, nil) 
     let attStr = NSMutableAttributedString(string: text as String) 
     attStr.addAttribute(String(kCTFontAttributeName), value:myFont, range: NSRange(location: 0, length: attStr.length)) 
     let frameSetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString) 
     let path = CGPath(rect: CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height), transform: nil) 
     let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 
     guard let lines = CTFrameGetLines(frame) as? [CTLine] else { 
      return [] 
     } 

     var linesArray = [String]() 

     for line in lines { 
      let lineRange = CTLineGetStringRange(line) 
      let range = NSRange(location: lineRange.location, length: lineRange.length) 
      let lineString = text.substring(with: range) 
      linesArray.append(lineString as String) 
     } 

     return linesArray 
    } 
}