swift fonts uitextview nsattributedstring

swift - Texto atribuido, reemplace una fuente específica por otra usando veloz



fonts uitextview (2)

Hay un método llamado attributesAtIndex(_:effectiveRange:) . Este método devuelve un diccionario del que puede obtener la fuente.

Deberá iterar sobre cada índice para almacenar las fuentes. Será lento, porque en los archivos de texto la fuente podría cambiar cada carácter. Así que recomendaría hacer esto fuera del hilo principal.

Estoy usando texto atribuido en una UITextView. El texto contiene muchas fuentes.

Estoy buscando una manera de reemplazar una fuente en particular por otra.

Cualquier enfoque rápido para esto? :)


Mi código estará en Objective-C, pero como usamos ambos CocoaTouch, debería ser la misma lógica.

El método que uso es enumerateAttribute:inRange:options:usingBlock: para buscar solo NSFontAttributeName .

Hay otro punto que no se discute: cómo reconocer que la fuente es la que se busca. ¿Está buscando familyName , fontName (propiedad de UIFont ? Incluso en la misma familia, la fuente puede ser muy diferente y es posible que desee buscar realmente el que coincida exactamente con el mismo nombre. He discutido una vez sobre los nombres de fuentes aquí . Puede encontrarlo interesante en su caso. Tenga en cuenta que hay métodos (que yo no sabía en ese momento) que pueden obtener el nombre en negrita de la fuente si está disponible (o en cursiva, etc.)

El código principal en Objective-C es este:

[attrString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, [attrString length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { UIFont *currentFont = (UIFont *)value; //Font currently applied in this range if ([self isFont:currentFont sameAs:searchedFont]) //This is where it can be tricky { [attrString addAttribute:NSFontAttributeName value:replacementFont range:range]; } }];

Posible cambio / adaptación según sus necesidades: cambie la fuente, pero no el tamaño:

[attrString addAttribute:NSFontAttributeName value:[UIFont fontWithName:replaceFontName size:currentFont.pointSize]; range:range];

Código de prueba de muestra:

UIFont *replacementFont = [UIFont boldSystemFontOfSize:12]; UIFont *searchedFont = [UIFont fontWithName:@"Helvetica Neue" size:15]; UIFont *normalFont = [UIFont italicSystemFontOfSize:14]; NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:@"Lorem ipsum dolor sit amet,"]; NSAttributedString *attrStr1 = [[NSAttributedString alloc] initWithString:@"consectetuer adipiscing elit." attributes:@{NSFontAttributeName:searchedFont, NSForegroundColorAttributeName:[UIColor redColor]}]; NSAttributedString *attrStr2 = [[NSAttributedString alloc] initWithString:@" Aenean commodo ligula eget dolor." attributes:@{NSFontAttributeName:normalFont}]; NSAttributedString *attrStr3 = [[NSAttributedString alloc] initWithString:@" Aenean massa." attributes:@{NSFontAttributeName:searchedFont}]; NSAttributedString *attrStr4 = [[NSAttributedString alloc] initWithString:@"Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim."]; [attrString appendAttributedString:attrStr1]; [attrString appendAttributedString:attrStr2]; [attrString appendAttributedString:attrStr3]; [attrString appendAttributedString:attrStr4]; NSLog(@"AttrString: %@", attrString); [attrString enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, [attrString length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { UIFont *currentFont = (UIFont *)value; if ([self isFont:currentFont sameAs:searchedFont]) { [attrString addAttribute:NSFontAttributeName value:replacementFont range:rangeEffect]; } }]; NSLog(@"AttrString Changed: %@", attrString);

Con la solución de @TigerCoding , aquí está el código posible:

NSInteger location = 0; while (location < [attrString length]) { NSRange rangeEffect; NSDictionary *attributes = [attrString attributesAtIndex:location effectiveRange:&rangeEffect]; if (attributes[NSFontAttributeName]) { UIFont *font = attributes[NSFontAttributeName]; if ([self isFont:font sameAs:searchedFont]) { [attrString addAttribute:NSFontAttributeName value:replacementFont range:rangeEffect]; } } location+=rangeEffect.length; }

Como nota al margen: algunas optimizaciones para probar (pero necesitarán algunas investigaciones). Creo que a partir de algunos ejemplos, si aplicas el mismo atributoS para dos rangos consecutivos, NSAttributedString los "agregará" en uno, en caso de que tengas miedo de aplicar el mismo efecto de forma consecutiva. Entonces, la pregunta es si usted tiene @{NSFontAttributeName:font1, NSForegroundColorAttributeName:color1} para el rango 0,3 y @{NSFontAttributeName:font1, NSForegroundColorAttributeName:color2} para el rango 3,5 Will enumerateAttribute:inRange:options:usingBlock: return you el rango 0,5? ¿Será más rápido que enumerar cada índice?