Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kerning in iOS UITextView

Tags:

For what apparently is a 'bug,' UITextView does not seem to support kerning like other UIKit Elements. Is there a workaround to get kerning working?

To be clear, I'm talking about the spacing in between pairs of characters that are defined in the font file, not the general spacing between all characters. Using an NSAttributedString with the NSKernAttributeName will adjust the spacing between all characters, but the built in character pairs still don't work.

For Example:

enter image description here

Is there a workaround to fix this?

One simple workaround I have discovered is to add css styles to the UITextView which enable kerning. If I use the undocumented method setContentToHTMLString: I can inject the css to the secret webview within the text view.

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]; 

This fixes the problem immediately; however, it seems very likely this will get the app rejected. Is there a safe way to sneak some css into the text view?

Other workarounds I have experimented with include:

Using a webview and the contenteditable property. This isn't ideal because webview does a bunch of extra stuff that gets in the way, for example the input accessory view which can't easily be hidden.

Subclassing a UITextView and rendering text manually with core text. This is more complex than I'd hoped because all the selections stuff needs to be reconfigured as well. Because of UITextView's private subclasses of UITextPosition and UITextRange this is a huge pain in the ass if not completely impossible.

like image 847
Anthony Mattox Avatar asked Nov 05 '12 19:11

Anthony Mattox


People also ask

What is kerning in Swift?

Kerning defines the offset, in points, that a text view should shift characters from the default spacing. Use positive kerning to widen the spacing between characters. Use negative kerning to tighten the spacing between characters.

How do I change kerning in font?

To edit a kerning combination, click on the second class (or glyph) in the pair and then drag it closer or farther to the first class (or glyph). You can also do this by using the cursor keys ← for moving the glyphs closer and → for moving them farther.

What font size is used for kerning?

Kerning values Different fonts may use different units, but common values are 1000 and 2048 units/em.


2 Answers

You are right that your app would probably be rejected by using @selector(setContentToHTMLString:). You can however use a simple trick to construct the selector dynamically so that it will not be detected during validation.

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 } 

By wrapping the call inside a @try/@catch block, you also ensure that your app will not crash if the setContentToHTMLString: method is removed in a future version of iOS.

Using private APIs is generally not recommended, but in this case I think it totally makes sense to use a small hack vs rewriting UITextView with CoreText.

like image 80
0xced Avatar answered Sep 27 '22 19:09

0xced


After researching this a bit I found that the reason for the missing Kerning is that UITextView internally uses a UIWebDocumentView which has Kerning turned off by default.

Some infos about the inner workings of UITextView: http://www.cocoanetics.com/2012/12/uitextview-caught-with-trousers-down/

Unfortunately there is no sanctioned method to enable Kerning, I would definitely advise against using a hack using a camouflaged selector.

Here's my Radar, I suggest you dupe it: http://www.cocoanetics.com/2012/12/radar-uitextview-ignores-font-kerning/

In this I argue that when setting text on UITextView via setAttributedText we developers expect for Kerning to be on by default because that is how it would most closely match output of rendering the text via CoreText.

like image 40
Cocoanetics Avatar answered Sep 27 '22 21:09

Cocoanetics