Базовый текст / NSStringDrawing - CFAttributedStringRef / NSAttributedString - изменение размера шрифта
Случай: приписанная строка уже создана. Как изменить размер строки?
Я думаю, мы могли бы либо
A) Обновление pointSize для всех шрифтов в приписанной строке
Б) Нарисуйте приписанную строку с некоторым преобразованием
3 ответа
Это отлично работает как на Mac OS, так и на iOS
@implementation NSAttributedString (Scale)
- (NSAttributedString *)attributedStringWithScale:(double)scale
{
if(scale == 1.0)
{
return self;
}
NSMutableAttributedString *copy = [self mutableCopy];
[copy beginEditing];
NSRange fullRange = NSMakeRange(0, copy.length);
[self enumerateAttribute:NSFontAttributeName inRange:fullRange options:0 usingBlock:^(UIFont *oldFont, NSRange range, BOOL *stop) {
double currentFontSize = oldFont.pointSize;
double newFontSize = currentFontSize * scale;
// don't trust -[UIFont fontWithSize:]
UIFont *scaledFont = [UIFont fontWithName:oldFont.fontName size:newFontSize];
[copy removeAttribute:NSFontAttributeName range:range];
[copy addAttribute:NSFontAttributeName value:scaledFont range:range];
}];
[self enumerateAttribute:NSParagraphStyleAttributeName inRange:fullRange options:0 usingBlock:^(NSParagraphStyle *oldParagraphStyle, NSRange range, BOOL *stop) {
NSMutableParagraphStyle *newParagraphStyle = [oldParagraphStyle mutableCopy];
newParagraphStyle.lineSpacing *= scale;
newParagraphStyle.paragraphSpacing *= scale;
newParagraphStyle.firstLineHeadIndent *= scale;
newParagraphStyle.headIndent *= scale;
newParagraphStyle.tailIndent *= scale;
newParagraphStyle.minimumLineHeight *= scale;
newParagraphStyle.maximumLineHeight *= scale;
newParagraphStyle.paragraphSpacing *= scale;
newParagraphStyle.paragraphSpacingBefore *= scale;
[copy removeAttribute:NSParagraphStyleAttributeName range:range];
[copy addAttribute:NSParagraphStyleAttributeName value:newParagraphStyle range:range];
}];
[copy endEditing];
return copy;
}
@end
Удачного кодирования
У меня это работает со следующим кодом. Одна ошибка, хотя, если некоторый текст в приписанной строке не был установлен атрибут шрифта, он не будет обновлен. Поэтому я должен был все заключить в атрибуты шрифта.
- (void)recalculateSizeChangeInAttributedString {
if(self.attributedStringOriginal == nil) {
self.attributedStringOriginal = [self.attributedString copy];
}
CFMutableAttributedStringRef tempString = CFAttributedStringCreateMutableCopy(CFAllocatorGetDefault(), self.attributedStringOriginal.length, (CFMutableAttributedStringRef)self.attributedStringOriginal);
int lastIndex = 0;
int limit = CFAttributedStringGetLength(tempString);
for (int index = 0; index < limit;) {
CFRange inRange = CFRangeMake(0, limit - index);
CFRange longestEffective;
CTFontRef font = (CTFontRef)CFAttributedStringGetAttribute(tempString, index, kCTFontAttributeName, &longestEffective);
if(font != nil) {
// log for testing
NSLog(@"index: %i, range: %i - %i, longest: %i - %i, attribute: %@",
index, inRange.location,
inRange.location + inRange.length,
longestEffective.location, longestEffective.location + longestEffective.length,
@"..."
);
// alter the font and set the altered font/attribute
int rangeEnd = longestEffective.length != 0 ? longestEffective.length : 1;
CTFontRef modifiedFont = CTFontCreateCopyWithAttributes(font, CTFontGetSize((CTFontRef)font) * sizeFactor, NULL, NULL);
CFAttributedStringSetAttribute(tempString, CFRangeMake(index, rangeEnd), kCTFontAttributeName, modifiedFont);
CFRelease(modifiedFont);
}
// make next loop continue where current attribute ended
index += longestEffective.length;
if(index == lastIndex)
index ++;
lastIndex = index;
}
self.attributedString = (NSMutableAttributedString *)tempString;
CFRelease(tempString);
}
Я считаю, что разбор это единственный способ. Приписанная строка может иметь довольно сложный формат, ваша задача - увеличить размер шрифта.
Однако, если вам нужен этот трюк для рендеринга, вы можете избежать разбора строк - используйте масштабное преобразование для увеличения размера текста.