23

对于显然是“错误”的东西,UITextView 似乎不像其他 UIKit 元素那样支持字距调整。是否有解决方法可以使字距调整工作?

为了清楚起见,我说的是字体文件中定义的字符对之间的间距,而不是所有字符之间的一般间距。使用NSAttributedStringwithNSKernAttributeName将调整所有字符之间的间距,但内置的字符对仍然不起作用。

例如:

在此处输入图像描述

有没有解决方法来解决这个问题?

我发现的一种简单解决方法是将 css 样式添加到启用字距调整的 UITextView。如果我使用未记录的方法setContentToHTMLString:,我可以将 css 注入文本视图中的秘密 webview。

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

这可以立即解决问题;但是,这似乎很可能会导致应用被拒绝。有没有一种安全的方法可以将一些 CSS 潜入文本视图?

我尝试过的其他解决方法包括:

使用 webview 和 contenteditable 属性。这并不理想,因为 webview 做了很多额外的事情,例如不容易隐藏的输入附件视图。

使用核心文本手动子类化UITextView和渲染文本。这比我希望的要复杂,因为所有选择的东西也需要重新配置。由于UITextView's 的私有子类,如果不是完全不可能的话UITextPositionUITextRange这是一个巨大的痛苦。

4

6 回答 6

37

你是对的,你的应用程序可能会被使用拒绝@selector(setContentToHTMLString:)。但是,您可以使用一个简单的技巧来动态构造选择器,以便在验证期间不会检测到它。

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
}

setContentToHTMLString:通过将调用包装在 @try/@catch 块中,您还可以确保如果在未来版本的 iOS 中删除该方法,您的应用程序不会崩溃。

通常不建议使用私有 API,但在这种情况下,我认为使用小技巧与使用 CoreText 重写 UITextView 完全有意义。

于 2012-11-14T21:43:31.473 回答
3

经过一番研究后,我发现缺少 Kerning 的原因是 UITextView 内部使用了默认情况下关闭 Kerning 的 UIWebDocumentView。

关于 UITextView 内部工作的一些信息:http: //www.cocoanetics.com/2012/12/uitextview-caught-with-trousers-down/

不幸的是,没有认可的方法来启用字距调整,我绝对建议不要使用伪装选择器的黑客攻击。

这是我的雷达,我建议你欺骗它: http: //www.cocoanetics.com/2012/12/radar-uitextview-ignores-font-kerning/

在此我认为,当通过 setAttributedText 在 UITextView 上设置文本时,我们开发人员希望默认情况下 Kerning 处于打开状态,因为这将最接近通过 CoreText 呈现文本的输出。

于 2012-12-16T18:54:46.163 回答
1

试试这个:

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

它在我的测试中有效。当然,我还没有在应用商店中尝试过。

于 2012-11-15T06:36:11.977 回答
0

你看过这里吗: https ://github.com/AliSoftware/OHAttributedLabel ?查看这个项目,应用商店中似乎有几个应用程序正在使用标记(由此类提供)。也许您可以使用这个类或从中收集一些实现想法。也许您的应用程序原样会通过集合。

于 2012-11-09T15:48:06.910 回答
0

在 iOS6 中,UITextView有一个新属性attributedText,您可以为其分配一个NSAttributedString. 我还没有尝试过,但是如果你设置文本视图的这个属性而不是text属性,看看你是否得到了你想要的字距调整会很有趣。它具有作为公共接口的额外好处。

于 2012-11-14T21:51:30.420 回答
-1

没有必要诉诸私有方法。attributedText您可以通过订阅通知在每次文本更改时动态更改文本字段的属性来轻松伪造它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];
}
于 2014-03-14T15:42:43.950 回答