2010-12-12 24 views
12

¿Hay una manera fácil de obtener (o simplemente mostrar) el texto de una línea determinada en un UILabel?¿Cómo obtener texto de la enésima línea de UILabel?

Mi UILabel está mostrando correctamente mi texto y lo está colocando de forma hermosa, pero ocasionalmente necesito poder mostrar ciertas líneas, pero obviamente necesito saber cómo UILabel ha posicionado todo para hacerlo.

Sé que esto podría hacerse fácilmente con una subcadena, pero necesitaría saber el punto de inicio y fin de la línea.

Ocasionalmente podía desplazar el UILabel si había algún tipo de desplazamiento en el marco de UILabel y ocultar el resto del contenido que no quería ver.

No he podido descubrir nada que muestre cómo esto podría hacerse fácilmente. ¿Alguien tiene alguna buena idea?

Gracias

iphaaw

Respuesta

4

No creo que haya una forma nativa para hacer esto (como un método "takethenline").
Puedo encontrar una solución difícil pero no estoy seguro de cuál sea la mejor.
Puede dividir su etiqueta en una matriz de palabras.
entonces se podría bucle de la matriz y comprobar la altura de texto hasta que la palabra así:

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 los cambios de altura, que significa que hay un salto de línea antes de la palabra.
No puedo verificar si la sintaxis está escrita correctamente ahora, por lo que debe verificarla usted mismo.

0

Si todos los caracteres se muestran en el mismo tamaño, es decir, que están encerrados en una caja de tamaño común, puede explotar eso. (Esto parece ser el caso de los caracteres japoneses, por ejemplo.)

lo contrario se puede consultar el tamaño de cada carácter en la fuente de la pantalla y calcular lo que la línea tendría que ser.

La única preocupación es que su cálculo puede estar en desacuerdo con lo que Apple está haciendo detrás de escena, en cuyo caso, le recomiendo que se tome la molestia de anular el dibujo del marco de texto. Busque texto principal en los documentos para esto.

(que puede haber estado haciendo esto mal, pero no he encontrado el método de Apple como se indica en los documentos era muy precisa, por lo que hice algo más a mí mismo.)

19

que tienen una mejor manera de encontrar lo .

Puede obtenerlo con la ayuda de CoreText.framework.

1.Add CoreText.framework.
2.Import #import <CoreText/CoreText.h>.
A continuación, utilice a continuación el método:

- (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; 
} 

llamar a este método: -

NSArray *linesArray = [self getLinesArrayOfStringInLabel:yourLabel]; 

Ahora puede utilizar linesArray.

+0

awesome answer .... heads up .... guardado mucho de mi tiempo. gracias .. –

+0

fabuloso, genial. Muchas gracias. –

5

respuesta adecuada con la liberación !!!!

-(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 2 (Xcode 7) versión (probado a, y editado de la respuesta 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

Debe reemplazar el siguiente código ** let text: NSString = label.text! // TODO: ¿Está seguro? ** con ** guard let text: NSString = self.text else { return [] } ** –

+4

Al principio no funcionó para mí - el número de líneas calculadas más que el número real. pero luego cambié la línea con CGPathAddRect a: CGPathAddRect (ruta, nada, CGRectMake (0, 0, rect.size.width + 15, 100,000)) y funcionó como se suponía. – locomotion

+0

esto no es confiable. ver: https://stackoverflow.com/questions/46923039/get-each-line-of-text-in-a-uilabel – chicobermuda

1

Swift 3 - Xcode 8.1

he creado un código de la anterior nswers para crear un Swift 3 compatible con Xcode 8.1 extension a UILabel devolviendo la primera línea de la etiqueta.

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 
    } 
} 

Para usarlo, simple llamada firstLineString en su UILabel ejemplo a esto:

let firstLine = myLabel.firstLineString 
2

Ésta es la versión Swift 3 para conseguir todas las líneas en la etiqueta. (@fredpi tiene una respuesta similar, pero es solo para la primera línea)

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 
    } 
} 
Cuestiones relacionadas