Изменение размера шрифта 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, потому что он также будет использоваться другими платформами.

У кого-нибудь есть идеи, почему это происходит?


person Marion McKelvie    schedule 08.01.2014    source источник


Ответы (5)


Я также столкнулся с этой проблемой, я исправил ее, перейдя к атрибутам и сбросив старый размер шрифта следующим образом.

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];
person KishoreThindaak    schedule 08.01.2014
comment
Спасибо за ответ, по крайней мере я не один такой! Я надеялся, что мне не придется снова устанавливать размер, так как это было единственное, что я мог придумать. - person Marion McKelvie; 09.01.2014
comment
У меня также есть эта проблема, и я искал решение, но пока не нашел. Если у вас есть, пожалуйста, опубликуйте его. Спасибо - person Metodij Zdravkin; 15.01.2014
comment
Похоже, это единственный. Установите переменную с помощью fontSize и используйте ее вместо фиксированного размера. Сделал работу за меня! - person Metodij Zdravkin; 31.01.2014
comment
Это было очень полезно, спасибо. У меня тоже была эта проблема. В моем случае приведенное выше решение потеряет другие атрибуты, связанные со шрифтом. Я преодолел это с помощью UIFont *newfont = [UIFont fontWithDescriptor:[oldFont fontDescriptor] size:size] - person Fergal Rooney; 14.01.2015
comment
Есть ли какие-либо обновления по этому поводу? - person KishoreThindaak; 25.02.2015
comment
@FergalRooney Я думаю, что newFont = oldFont.fontWithSize(size) выполняет ту же работу, что и ваш код - person CedricSoubrie; 08.12.2016

Использование <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]];
}

Это устанавливает имя и размер шрифта, но не влияет на стили.

person danomatika    schedule 18.07.2014

Исправлено это волшебное поведение 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];
}
person k06a    schedule 12.10.2016
comment
Проголосовал за, потому что, хотя это ужасный кладж, он ужасен, потому что он необходим (я не могу найти другого обходного пути), а не из-за его кода - молодец! - person Grimxn; 13.04.2017
comment
@Grimxn Я только что обновил свой ответ последней версией кода. - person k06a; 13.04.2017

Версия 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
person Fangming    schedule 16.06.2017

Это не совсем ответ, скорее альтернатива и комментарий к различным другим данным ответам, так что приносим свои извинения.

Ответы, данные @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)
    }
}
person Grimxn    schedule 07.08.2017