Kerning w iOS UITextView
Dla tego, co najwyraźniej jest 'błędem', UITextView nie wydaje się wspierać kerningu, jak inne elementy UIKit. Czy istnieje obejście, aby kerning działał?
Żeby było jasne, mówię o odstępach między parami znaków, które są zdefiniowane w pliku czcionki, a nie o ogólnym odstępie między wszystkimi znakami. Użycie {[1] } z NSKernAttributeName
dostosuje odstępy między wszystkimi znakami, ale wbudowane pary znaków nadal nie działają.
Dla Przykład:
Czy istnieje obejście tego problemu?
Jednym z prostych rozwiązań, które odkryłem, jest dodanie stylów css do UITextView, które umożliwiają kerning. Jeśli użyję nieudokumentowanej metody setContentToHTMLString:
, mogę wprowadzić css do tajnego widoku sieci Web w widoku tekstowym.
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];
To rozwiązuje problem natychmiast; jednak wydaje się bardzo prawdopodobne, że spowoduje to odrzucenie aplikacji. Czy istnieje bezpieczny sposób, aby przemycić css do widoku tekstowego?
Inne obejścia, z którymi eksperymentowałem, obejmują:
Używanie widoku sieci Web i właściwości contenteditable. Nie jest to idealne rozwiązanie, ponieważ webview robi kilka dodatkowych rzeczy, które wchodzą w drogę, na przykład widok akcesoriów wejściowych, które nie mogą być łatwo ukryte.
Podklasowanie a UITextView
i ręczne renderowanie tekstu z tekstem głównym. Jest to bardziej złożone, niż się spodziewałem, ponieważ wszystkie elementy selekcji również wymagają rekonfiguracji. Ze względu na prywatne podklasy UITextView
z UITextPosition
i UITextRange
to to ogromny wrzód na dupie, jeśli nie całkowicie niemożliwe.
6 answers
Masz rację, że Twoja aplikacja prawdopodobnie zostanie odrzucona przez użycie @selector(setContentToHTMLString:)
. Można jednak użyć prostej sztuczki, aby dynamicznie skonstruować selektor, aby nie został wykryty podczas walidacji.
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
}
Owijając wywołanie wewnątrz bloku @ try/ @ catch, możesz również upewnić się, że aplikacja nie ulegnie awarii, jeśli Metoda setContentToHTMLString:
zostanie usunięta w przyszłej wersji iOS.
Korzystanie z prywatnych interfejsów API nie jest ogólnie zalecane, ale w tym przypadku myślę, że całkowicie sensowne jest użycie małego hack vs przepisywanie UITextView z CoreText.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-14 21:43:31
Spróbuj tego:
[textView_ setValue:@"hello, <b>world</b>" forKey:@"contentToHTMLString"];
To działa w moim teście. Oczywiście nie próbowałem tego w app store.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-15 06:36:11
Po zbadaniu tego trochę odkryłem, że powodem braku kerningu jest to, że UITextView wewnętrznie używa UIWebDocumentView, który ma Kerning wyłączony domyślnie.
Kilka informacji o wewnętrznym działaniu UITextView: http://www.cocoanetics.com/2012/12/uitextview-caught-with-trousers-down/
Niestety nie ma usankcjonowanej metody umożliwiającej Kerningowanie, zdecydowanie odradzałbym użycie hacka przy użyciu zakamuflowanego selektora.
Oto mój Radar, proponuję oszukać: http://www.cocoanetics.com/2012/12/radar-uitextview-ignores-font-kerning/
W tym twierdzę, że podczas ustawiania tekstu na UITextView przez setAttributedText, Programiści oczekują, że Kerning będzie domyślnie włączony, ponieważ w ten sposób będzie najbardziej dopasowany do wyniku renderowania tekstu przez CoreText.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-16 18:54:46
Zajrzałeś tutaj: https://github.com/AliSoftware/OHAttributedLabel ? patrząc na ten projekt, wydaje się, że w app store jest kilka aplikacji, które używają znaczników (dostarczonych przez tę klasę). Być może mógłbyś użyć tej klasy lub zebrać z niej kilka pomysłów na implementację. Być może Twoja aplikacja w stanie, w jakim jest, przejdzie zbiórkę.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-09 15:48:06
Z iOS6, UITextView
posiada nowy atrybut attributedText
, do którego można przypisać NSAttributedString
. Nie próbowałem tego, ale byłoby interesujące zobaczyć, czy masz kerning, którego szukasz, jeśli ustawisz ten atrybut widoku tekstu, a nie atrybut text
. I ma dodatkową zaletę bycia interfejsem publicznym.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-14 21:51:30
Nie ma potrzeby uciekania się do prywatnych metod. Możesz go łatwo sfałszować, dynamicznie zmieniając Właściwość attributedText
pola tekstowego za każdym razem, gdy tekst się zmieni, subskrybując powiadomienie 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];
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-14 15:42:43