Kerning in iOS UITextView

前端 未结 6 880
北海茫月
北海茫月 2020-12-22 18:33

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

相关标签:
6条回答
  • 2020-12-22 18:58

    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.

    0 讨论(0)
  • 2020-12-22 19:07

    Try this:

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

    It works in my test. I haven't tried it in the app store of course.

    0 讨论(0)
  • 2020-12-22 19:08

    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.

    0 讨论(0)
  • 2020-12-22 19:09

    With iOS6, UITextView has a new attribute attributedText, to which you can assign an NSAttributedString. I have not tried it, but it would be interesting to see if you get the kerning you are after if you set this attribute of your text view rather than the text attribute. And it has the added benefit of being a public interface.

    0 讨论(0)
  • 2020-12-22 19:19

    Have you taken a look here: https://github.com/AliSoftware/OHAttributedLabel? Looking at this project, it appears that there are several apps in the app store that are using markup (provided by this class). Perhaps you could either use this class or glean some implementation ideas from it. Perhaps your app as-is will pass muster.

    0 讨论(0)
  • 2020-12-22 19:22

    There’s no need to resort to private methods. You can easily fake it by dynamically changing the attributedText property of the text field each time the text changes by subscribing to the UITextFieldTextDidChangeNotification notification:

    - (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];
    }
    
    0 讨论(0)
提交回复
热议问题