2011-05-20 16 views
16

cómo encontrar qué texto es visible en una UITextView desplazable y no editable?ios: cómo encontrar el rango visible de texto en UITextView?

por ejemplo, podría tener que mostrar párrafo siguiente, entonces quiero encontrar el rango de texto visible actual y utilizarla para calcular el rango apropiado y utilizar scrollRangeToVisible: para desplazar la vista de texto

Respuesta

4

La forma en que lo haría es calcular todos los tamaños de cada párrafo. Con sizeWithFont: constrainedToSize: lineBreakMode:

podrá entonces determinar qué párrafo es visible desde [textView contentOffset].

para desplazarse, no use scrollRangeToVisible, simplemente use setContentOffset: El parámetro CGPoint y para esto debe ser la suma de todos los tamaños de altura hasta el siguiente párrafo, o simplemente agregue el textView.frame.size.height, si eso está más cerca que el comienzo del siguiente párrafo.

Esto tiene sentido?

en respuesta a petición de éstos Comentario Código de abajo (no probado):

CGFloat paragraphOffset[MAX_PARAGRAPHS]; 

    CGSize constraint = CGSizeMake(widthOfTextView, 999999 /*arbitrarily large number*/); 
    NSInteger paragraphNo = 0; 
    CGFloat offset = 0; 

    for (NSString* paragraph in paragraphs) { 
     paragraphOffset[paragraphNo++] = offset; 
     CGSize paragraphSize = [paragraph sizeWithFont:textView.font constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap]; 
     offset += paragraphSize.height; 
    } 

    // find visible paragraph 
    NSInteger visibleParagraph = 0; 
    while (paragraphOffset[visibleParagraph++] < textView.contentOffset.y); 


    // scroll to paragraph 6 
    [textView setContentOffset:CGPointMake(0, paragraphOffset[6]) animated:YES]; 
+0

¿Puedes darnos algún código de ejemplo? No estoy seguro de cómo sizeWithFont: constrainedToSize: lineBreakMode: funciona, ¿qué es para constrainedToSize: argument? –

+0

añadió el código anterior. Los párrafos FYI son un NSArray de las cadenas de párrafo –

+2

. Tenga en cuenta que puede reemplazar el 9999999 por FLT_MAX (variable de iPhone predeterminada para un valor grande) – Niko

1

Una opción que tiene es utilice un UIWebView en lugar de un UITextView. Luego puede usar anclajes y javascript para desplazarse a los lugares apropiados en el texto. Probablemente pueda insertar los anclajes programáticamente al comienzo de cada párrafo para que sea más fácil.

+0

No estoy familiarizado con javascript y cosas html complejas, ¿me puede dar algún ejemplo? También UIWebView puede ser más difícil de tratar que UITextView –

+0

@ xlc0212: Si no necesita editar, usar una UIWebview será mucho más fácil (y probablemente más rápido) que calcular el tamaño de texto de una UITextView cada vez que necesite desplazarse. Solo busca lo que son los "anclajes html", no es nada complejo. – roop

7

encuentro otra solución aquí. Es una mejor manera de resolver este problema en mis ojos. https://stackoverflow.com/a/9283311/889892

Dado que UITextView es una subclase de UIScrollView, su propiedad de límites refleja la parte visible de su sistema de coordenadas. Así que algo como esto debería funcionar:

-(NSRange)visibleRangeOfTextView:(UITextView *)textView { 
    CGRect bounds = textView.bounds; 
    UITextPosition *start = [textView characterRangeAtPoint:bounds.origin].start; 
    UITextPosition *end = [textView characterRangeAtPoint:CGPointMake(CGRectGetMaxX(bounds), CGRectGetMaxY(bounds))].end; 
    return NSMakeRange([textView offsetFromPosition:textView.beginningOfDocument toPosition:start], 
     [textView offsetFromPosition:start toPosition:end]); 
} 

Esto supone un diseño de texto de arriba a abajo, de izquierda a derecha. Si desea que funcione para otras instrucciones de diseño, tendrá que trabajar más duro. :)

+0

Cuando dice "algo así debería funcionar", ¿lo ha intentado realmente? Esto está devolviendo casi el triple del rango del texto visual real para mí. Gracias. –

2

Si desea una solución rápida utilizo este:

public extension UITextView { 

    public var visibleRange: NSRange? { 
     if let start = closestPositionToPoint(contentOffset) { 
      if let end = characterRangeAtPoint(CGPointMake(contentOffset.x + CGRectGetMaxX(bounds), contentOffset.y + CGRectGetMaxY(bounds)))?.end { 
       return NSMakeRange(offsetFromPosition(beginningOfDocument, toPosition: start), offsetFromPosition(start, toPosition: end)) 
      } 
     } 
     return nil 
    } 
} 
0

Swift 3.0/3.1 solución basada en "fideos de la Muerte" como respuesta.

public extension UITextView { 

    public var visibleRange: NSRange? { 
     if let start = closestPosition(to: contentOffset) { 
      if let end = characterRange(at: CGPoint(x: contentOffset.x + bounds.maxX, y: contentOffset.y + bounds.maxY))?.end { 
       return NSMakeRange(offset(from: beginningOfDocument, to: start), offset(from: start, to: end)) 
      } 
     } 
     return nil 
    } 
} 
Cuestiones relacionadas