objective-c ios css uitextview kerning

objective c - Kerning en iOS UITextView



objective-c css (6)

Para lo que aparentemente es un ''error'', UITextView no parece admitir el kerning como otros elementos UIKit. ¿Hay alguna solución para hacer funcionar el kerning?

Para ser claros, estoy hablando del espaciado entre pares de caracteres que se definen en el archivo de fuente, no del espaciado general entre todos los caracteres. El uso de una NSAttributedString con el NSKernAttributeName ajustará el espaciado entre todos los caracteres, pero los pares de caracteres integrados todavía no funcionan.

Por ejemplo:

¿Hay una solución para solucionar este problema?

Una solución simple que he descubierto es agregar estilos css al UITextView que habilite el kerning. Si utilizo el método no documentado setContentToHTMLString: puedo inyectar el css a la vista web secreta dentro de la vista de texto.

NSString *css = @"*{text-rendering: optimizeLegibility;}"; NSString *html = [NSString stringWithFormat:@"<html><head><style>%@</style></head><body>Your HTML Text</body></html>", css]; [textView performSelector:@selector(setContentToHTMLString:) withObject:html];

Esto soluciona el problema inmediatamente; Sin embargo, parece muy probable que esto haga que la aplicación sea rechazada. ¿Hay una manera segura de colar algunos css en la vista de texto?

Otras soluciones con las que he experimentado incluyen:

Usando una vista web y la propiedad contenteditable. Esto no es ideal porque webview hace un montón de cosas adicionales que se interponen en el camino, por ejemplo, la vista de accesorios de entrada que no se puede ocultar fácilmente.

UITextView un UITextView y renderizando el texto manualmente con el texto central. Esto es más complejo de lo que esperaba porque todas las selecciones también deben reconfigurarse. Debido a las subclases privadas de UITextPosition de UITextPosition y UITextRange esto es un gran dolor en el culo, si no es completamente imposible.


¿Has echado un vistazo aquí: https://github.com/AliSoftware/OHAttributedLabel ? Al observar este proyecto, parece que hay varias aplicaciones en la tienda de aplicaciones que están utilizando el marcado (proporcionado por esta clase). Tal vez podrías usar esta clase o recoger algunas ideas de implementación. Tal vez tu aplicación tal como está pasará el examen.


Con iOS6, UITextView tiene un nuevo atributo attributedText , al que puede asignar una NSAttributedString . No lo he probado, pero sería interesante ver si obtienes el kerning que buscas si configuras este atributo de tu vista de texto en lugar del atributo text . Y tiene el beneficio adicional de ser una interfaz pública.


Después de investigar esto un poco, descubrí que la razón del Kerning faltante es que UITextView utiliza internamente un UIWebDocumentView que tiene Kerning desactivado de forma predeterminada.

Algunas informaciones sobre el funcionamiento interno de UITextView: http://www.cocoanetics.com/2012/12/uitextview-caught-with-trousers-down/

Desafortunadamente, no existe un método autorizado para habilitar Kerning, definitivamente recomendaría no usar un truco con un selector camuflado.

Aquí está mi radar, te sugiero que lo engañes: http://www.cocoanetics.com/2012/12/radar-uitextview-ignores-font-kerning/

En este punto, sostengo que cuando configuramos el texto en UITextView a través de setAttributedText, los desarrolladores esperamos que Kerning esté activado de forma predeterminada, ya que es la forma más parecida a la salida de la representación del texto a través de CoreText.


No hay necesidad de recurrir a métodos privados. Puede falsificarlo fácilmente cambiando dinámicamente la propiedad UITextFieldTextDidChangeNotification campo de texto cada vez que el texto cambie suscribiéndose a la notificación UITextFieldTextDidChangeNotification :

- (void)viewDidLoad { // your regular stuff goes here [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textDidChangeNotification:) name:UITextFieldTextDidChangeNotification object:nil]; } - (void)textDidChangeNotification:(NSNotification *)notification { // you can of course specify other attributes here, such as font and text color CGFloat kerning = -3.; // change accordingly to your desired value NSDictionary *attributes = @{ NSKernAttributeName: @(kerning), }; UITextField *textField = [notification object]; textField.attributedText = [[NSAttributedString alloc] initWithString:textField.text attributes:attributes]; }


Prueba esto:

[textView_ setValue:@"hello, <b>world</b>" forKey:@"contentToHTMLString"];

Funciona en mi prueba. No lo he probado en la tienda de aplicaciones, por supuesto.


Tiene razón en que su aplicación probablemente sea rechazada al usar @selector(setContentToHTMLString:) . Sin embargo, puede usar un truco simple para construir el selector dinámicamente para que no se detecte durante la validación.

NSString *css = @"*{text-rendering: optimizeLegibility;}"; NSString *html = [NSString stringWithFormat:@"<html><head><style>%@</style></head><body>Your HTML Text</body></html>", css]; @try { SEL setContentToHTMLString = NSSelectorFromString([@[@"set", @"Content", @"To", @"HTML", @"String", @":"] componentsJoinedByString:@""]); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" [textView performSelector:setContentToHTMLString withObject:html]; #pragma clang diagnostic pop } @catch (NSException *exception) { // html+css could not be applied to text view, so no kerning }

Al ajustar la llamada dentro de un bloque @ try / @ catch, también se asegura de que su aplicación no se bloquee si se setContentToHTMLString: método setContentToHTMLString: en una versión futura de iOS.

Generalmente no se recomienda el uso de API privadas, pero en este caso creo que tiene mucho sentido usar un pequeño truco contra la reescritura de UITextView con CoreText.