iphone - textfielddidchange - ios: ¿cómo encontrar cuál es el rango de texto visible en UITextView?
textfield swift 4 (5)
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 en otras direcciones de diseño, tendrá que trabajar más. :)
¿Cómo encontrar qué texto es visible en un UITextView desplazable y no editable?
por ejemplo, es posible que tenga que mostrar el siguiente párrafo, luego quiero encontrar el rango de texto visible actual y usarlo para calcular el rango apropiado y usar scrollRangeToVisible:
para desplazar la vista de texto
La forma en que lo haría es calcular todos los tamaños de cada párrafo. Con sizeWithFont: restricinedToSize: lineBreakMode:
entonces podrá averiguar qué párrafo es visible, desde [textView contentOffset].
para desplazarse, no use scrollRangeToVisible, solo use setContentOffset: El parámetro CGPoint y para esto debe ser la suma de todos los tamaños de altura al siguiente párrafo, o simplemente agregue el textView.frame.size.height, si está más cerca que comienzo del siguiente párrafo.
Esto tiene sentido?
En respuesta al comentario, solicite el siguiente código (sin probar):
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];
Si quieres una solución Swift utilizo esto:
Swift 2
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
}
}
Swift 3
public extension UITextView {
public var visibleRange: NSRange? {
guard let start = closestPosition(to: contentOffset),
end = characterRange(at: CGPoint(x: contentOffset.x + bounds.maxX,
y: contentOffset.y + bounds.maxY))?.end
else { return nil }
return NSMakeRange(offset(from: beginningOfDocument, to: start), offset(from: start, to: end))
}
}
Solución Swift 3.0 / 3.1 basada en la respuesta " Noodle of Death " .
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
}
}
Una opción que tiene es usar un UIWebView en lugar de un UITextView. Luego puede usar los anclajes y javascript para desplazarse a los lugares apropiados en el texto. Probablemente pueda insertar los anclajes al comienzo de cada párrafo para facilitar esto.