Изменение размера шрифта ios7 при создании nsattributedstring из html
У меня есть UITextView, где я управляю NSAttributedString, первоначально введенным как обычно с клавиатуры. Я сохраняю атрибутированную строку как HTML, которая выглядит нормально.
Когда я снова загружу его и преобразую обратно в атрибутную строку из HTML, размер шрифта изменится.
Например, HTML при загрузке выглядит следующим образом:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<title></title>
<meta name="Generator" content="Cocoa HTML Writer">
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 21.0px Helvetica; color: #000000; -webkit-text- stroke: #000000}
span.s1 {font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 21.00pt; font-kerning: none}
</style>
</head>
<body>
<p class="p1"><span class="s1">There is some text as usual lots of text</span></p>
</body>
</html>
Я конвертирую его и проверяю атрибуты со следующим кодом:
// convert to attributed string
NSError *err;
NSAttributedString *as = [[NSAttributedString alloc] initWithData:data3
options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)}
documentAttributes:nil
error:&err] ;
NSMutableAttributedString *res = [as mutableCopy];
[res enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, res.length) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) {
if (value) {
UIFont *oldFont = (UIFont *)value;
NSLog(@"On Loading: Font size %f, in range from %d length %d", oldFont.pointSize, range.location, range.length);
}
}];
Результат показывает, что размер шрифта увеличился с 21 до 28:
On Loading: Font size 28.000000, in range from 0 length 40
On Loading: Font size 21.000000, in range from 40 length 1
В принципе, каждый раз, когда я загружаю строку, размер шрифта увеличивается. Мне нужно сохранить его как HTML, а не NSData, потому что он также будет использоваться другими платформами.
Есть ли у кого-нибудь идеи, почему это происходит?
Ответы
Ответ 1
Я также столкнулся с этой проблемой, я исправил ее, повторив атрибуты и перезапуская старый размер шрифта следующим образом
NSMutableAttributedString *res = [attributedText mutableCopy];
[res beginEditing];
[res enumerateAttribute:NSFontAttributeName
inRange:NSMakeRange(0, res.length)
options:0
usingBlock:^(id value, NSRange range, BOOL *stop) {
if (value) {
UIFont *oldFont = (UIFont *)value;
UIFont *newFont = [oldFont fontWithSize:15];
[res addAttribute:NSFontAttributeName value:newFont range:range];
}
}];
[res endEditing];
[self.textFileInputView setAttributedText:res];
Ответ 2
Использование <span>
и css работает для меня, следуя Анализ HTML в NSAttributedText - как установить шрифт?:
// HTML -> NSAttributedString
+ (NSAttributedString *)attributedStringFromHTML:(NSString *)html {
NSError *error;
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType};
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:[html dataUsingEncoding:NSUTF8StringEncoding] options:options documentAttributes:nil error:&error];
if(!attrString) {
NSLog(@"creating attributed string from HTML failed: %@", error.debugDescription);
}
return attrString;
}
// force font thrugh <span> & css
+ (NSAttributedString *)attributedStringFromHTML:(NSString *)html withFont:(UIFont *)font {
return [Util attributedStringFromHTML:[NSString stringWithFormat:@"<span style=\"font-family: %@; font-size: %f\";>%@</span>", font.fontName, font.pointSize, html]];
}
Это задает имя и размер шрифта, но не влияет на стили.
Ответ 3
Исправлено это волшебное поведение Apple со следующим кодом:
static CGFloat const kListsLeading = 10.0;
static CGFloat const kListsAdditionalShift = 4.0;
//
// Fix Apple magic 4/3 koefficient
// http://stackoverflow.com/questions/20992950/ios7-font-size-change-when-create-nsattributedstring-from-html
//
static NSAttributedString *DecreaseFontSizeBecauseOfAppleMagic(NSAttributedString *astr) {
NSMutableAttributedString *mastr = [astr mutableCopy];
[mastr enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0, astr.length) options:0 usingBlock:^(UIFont *_Nullable value, NSRange range, BOOL *_Nonnull stop) {
if (value) {
UIFont *font = [value fontWithSize:value.pointSize * 0.75];
[mastr addAttribute:NSFontAttributeName value:font range:range];
}
}];
[mastr enumerateAttribute:NSParagraphStyleAttributeName inRange:NSMakeRange(0, astr.length) options:0 usingBlock:^(NSParagraphStyle *_Nullable value, NSRange range, BOOL *_Nonnull stop) {
if (value) {
NSMutableParagraphStyle *style = [value mutableCopy];
style.minimumLineHeight *= 0.75;
if (style.firstLineHeadIndent == style.headIndent) {
style.firstLineHeadIndent *= 0.75;
style.headIndent *= 0.75;
}
else if (style.firstLineHeadIndent < kListsLeading) {
CGFloat shift = (kListsLeading - style.firstLineHeadIndent);
style.headIndent += shift + kListsAdditionalShift;
style.firstLineHeadIndent = kListsLeading;
NSMutableArray *tabs = [NSMutableArray array];
NSInteger index = 0;
for (NSTextTab *tab in style.tabStops) {
[tabs addObject:[[NSTextTab alloc] initWithTextAlignment:tab.alignment location:tab.location + shift + kListsAdditionalShift * (index ? 1 : 0) options:tab.options]];
index++;
}
style.tabStops = tabs;
}
style.tailIndent *= 0.75;
[mastr addAttribute:NSParagraphStyleAttributeName value:style range:range];
}
}];
return [mastr copy];
}
Ответ 4
версия Swift 3.0
С коэффициентом 0,75
yourAttrStr.beginEditing()
yourAttrStr.enumerateAttribute(NSFontAttributeName, in: NSMakeRange(0, yourAttrStr.length), options: .init(rawValue: 0)) {
(value, range, stop) in
if let font = value as? UIFont {
let resizedFont = font.withSize(font.pointSize * 0.75)
yourAttrStr.addAttribute(NSFontAttributeName, value: resizedFont, range: range)
}
}
yourAttrStr.endEditing()//yourAttrStrwill be the same size as html string
Ответ 5
Это не совсем ответ, больше альтернатива и комментарий к различным другим приведенным ответам, поэтому извиняйтесь.
Ответы, полученные @KishoreThindaak и @Danomatika, прекрасны, если вы знаете, какими должны быть размеры шрифта, но в моем приложении есть двойник Mac OS, который может генерировать текст любого размера и, следовательно, должен быть общим.
Ответ, заданный @k06a, работает для простого текста, но я обнаружил, что он не удался со встроенными стилями - особенно с несколькими стилями в строке, которая сама была встроена в тег <li>
.
После многих часов попыток исправить это, я боюсь, что я вообще отказался от HTML в качестве формата диска и принял RTF, который отлично работает и предоставляет RTF файл, который можно прочитать на всех платформах. Простой код для получения RTF ниже...
extension NSAttributedString {
func rtf(encoding: String.Encoding) -> Data? {
let options: [NSAttributedString.DocumentAttributeKey : Any] = [
NSAttributedString.DocumentAttributeKey.documentType: NSAttributedString.DocumentType.rtf,
NSAttributedString.DocumentAttributeKey.characterEncoding: encoding.rawValue
]
return try? self.data(from: NSMakeRange(0, self.length), documentAttributes: options)
}
class func from(rtfData data: Data, encoding: String.Encoding) -> NSAttributedString? {
let options: [NSAttributedString.DocumentReadingOptionKey : Any] = [
NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.rtf,
NSAttributedString.DocumentReadingOptionKey.characterEncoding: encoding.rawValue
]
return try? NSMutableAttributedString(data: data, options: options, documentAttributes: nil)
}
}