Nano Hash - криптовалюты, майнинг, программирование

Как рассчитать размер кадра для рисования CoreText по строке

Я пытаюсь динамически создавать страницы книги на основе длинного NSAttributedString, разделенного на части.

Сейчас я использую эту категорию для NSAttributedString:

@interface NSAttributedString (Height)
- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth;
@end

@implementation NSAttributedString (Height)

- (CGFloat)boundingHeightForWidth:(CGFloat)inWidth
{
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)self); 
    CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(inWidth, 10000), NULL);
    CFRelease(framesetter);
    return suggestedSize.height ;
}
@end

Поскольку я рисовал текст с помощью CTFramesetter, это сработало нормально, и правильная высота блока была возвращена правильно. К сожалению, теперь мне нужно рисовать текст построчно:

-(void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();

// Flip the coordinate system
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
//CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

NSArray *lines = (__bridge NSArray *)(CTFrameGetLines(ctFrame));

CFIndex lineCount = [lines count];

for(CFIndex idx = 0; idx < lineCount; idx++)
{
    // For each line found from where it starts and it's length
    CTLineRef line = CFArrayGetValueAtIndex((CFArrayRef)lines, idx);
    CFRange lineStringRange = CTLineGetStringRange(line);
    NSRange lineRange = NSMakeRange(lineStringRange.location, lineStringRange.length);
    // Get the line related string 
    NSString* lineString = [displayedString.string substringWithRange:lineRange];
    // Calculate it's range
    NSRange stringRange = NSMakeRange(lineStringRange.location, lineStringRange.length);

    static const unichar softHypen = 0x00AD;
    // Get the last char of the line
    unichar lastChar = [lineString characterAtIndex:stringRange.length-1];
    // Check if it's a soft hyphenation character
    if(softHypen == lastChar) {
        NSMutableAttributedString* lineAttrString = [[displayedString attributedSubstringFromRange:stringRange] mutableCopy];
        NSRange replaceRange = NSMakeRange(stringRange.length-1, 1);
        // Replace it with an hard hyphenation character
        [lineAttrString replaceCharactersInRange:replaceRange withString:@"-"];

        CTLineRef hyphenLine = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)lineAttrString);
        CTLineRef justifiedLine = CTLineCreateJustifiedLine(hyphenLine, 1.0, self.frame.size.width);

        CGFloat ascent;
        CGFloat descent;
        // Calculate the line height
        CTLineGetTypographicBounds(justifiedLine, &ascent, &descent, NULL);
        // Set the correct position for the line
        CGContextSetTextPosition(context, 0.0, idx*-(ascent + descent)-ascent);
        CTLineDraw(justifiedLine, context);
    }
    else{
        CGFloat ascent;
        CGFloat descent;
        // Calculate the line height
        CTLineGetTypographicBounds(line, &ascent, &descent, nil);
        CGFloat y = idx*-(ascent + descent)-ascent;
        // Set the correct position for the line
        CGContextSetTextPosition(context, 0.0, y);

        CTLineDraw(line, context);
    }
}

Это работает почти нормально, но не всегда. Иногда бывает такое:

Последняя строка вырезана

Как видите, последняя строка вырезана. Есть ли у кого-нибудь совет, чтобы исправить эту досадную проблему?


  • Возможно, это поможет вам: stackoverflow.com/questions/6338116/ - Кажется, существует несоответствие между высотой строки, которую предлагает CTFrameSetter, и высотой строки, содержащейся в самом шрифте. 10.03.2013

Ответы:


1

По некоторым причинам кажется, что (ascent + descent) не является правильной высотой для строки. На самом деле восходящий элемент + 1 + нижний элемент равен размеру пункта.

Просто изменить это:

CGContextSetTextPosition(context, 0.0, idx*-(ascent + descent)-ascent);

в это:

CGContextSetTextPosition(context, 0.0, idx*-(ascent - 1 + descent)-ascent);

сделал трюк. Ссылка: статья Cocoanetics о UIFont. Спасибо jverrijt за подсказку!

10.03.2013
  • 1 есть приближение ведущего. Вы должны получить истинное значение интерлиньяжа через CTLineGetTypographicBounds(justifiedLine, &ascent, &descent, &leading);. Также может быть лучше использовать CTFrameGetLineOrigins, если какие-либо из ваших линий имеют разную высоту. ???? 06.04.2021
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..