对于显然是'bug',UITextView似乎不像其他UIKit Elements那样支持字距调整。是否有解决方法来使字距调整工作?
要清楚,我在谈论字体文件中定义的字符对之间的间距,而不是所有字符之间的一般间距。使用NSAttributedString
和NSKernAttributeName
将调整所有字符之间的间距,但内置字符对仍无效。
例如:
有解决方法吗?
我发现的一个简单的解决方法是向UITextView添加css样式以启用字距调整。如果我使用未记录的方法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
的私有子类UITextPosition
和UITextRange
,如果不是完全不可能的话,这是一个巨大的痛苦。
答案 0 :(得分:36)
您是正确的,使用@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
}
通过将调用包装在@ try / @ catch块中,您还可以确保在将来的iOS版本中删除setContentToHTMLString:
方法时,您的应用不会崩溃。
通常不推荐使用私有API,但在这种情况下,我认为使用小型hack与使用CoreText重写UITextView完全有意义。
答案 1 :(得分:2)
在研究了一下之后,我发现缺少Kerning的原因是UITextView内部使用的UIWebDocumentView默认情况下关闭了Kerning。
有关UITextView内部工作原理的一些信息:http://www.cocoanetics.com/2012/12/uitextview-caught-with-trousers-down/
不幸的是,没有制裁方法来启用Kerning,我肯定会建议不要使用伪装选择器进行黑客攻击。
这是我的雷达,我建议你欺骗它:http://www.cocoanetics.com/2012/12/radar-uitextview-ignores-font-kerning/
在此我认为,当通过setAttributedText在UITextView上设置文本时,我们开发人员希望默认情况下启用Kerning,因为它最接近匹配通过CoreText呈现文本的输出。
答案 2 :(得分:1)
试试这个:
[textView_ setValue:@"hello, <b>world</b>" forKey:@"contentToHTMLString"];
它适用于我的测试。我当然没有在应用程序商店中尝试过它。
答案 3 :(得分:0)
你看过这里:https://github.com/AliSoftware/OHAttributedLabel?看看这个项目,app store中有几个使用标记的应用程序(由此类提供)。也许您可以使用此类或从中收集一些实现想法。也许你的应用程序将会通过审核。
答案 4 :(得分:0)
对于iOS6,UITextView
有一个新属性attributedText
,您可以为其分配NSAttributedString
。我没有尝试过,但是如果你设置了文本视图的这个属性而不是text
属性,那么看看你是否得到了你想要的字距就会很有趣。它还具有成为公共界面的额外好处。
答案 5 :(得分:-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];
}