Линии отсутствуют в высоком UILabel при встраивании NSTextAttachment
Я могу создать многострочный NSAttributedString
с помощью экранированных символов новой строки (@"\n"
). С iOS 7 я могу теперь внедрить UIImage
внутренние атрибутные строки (через NSTextAttachment
).
Я заметил, что всякий раз, когда я устанавливаю attributedText
of UILabel
в строку с несколькими строками со встроенным изображением, количество отображаемых строк обратно пропорционально высоте метки. Например, когда высота метки равна 80, появляются две строки; когда высота около 100, появляется только вторая строка; когда высота около 130, ничего не появляется.
Эта проблема возникла при попытке расположить несколько UILabels рядом друг с другом внутри UITableViewCell
и с ростом ярлыков (по вертикали) с высотой ячейки.
Может ли кто-нибудь объяснить, почему это происходит? Кто-нибудь знает обходные пути, которые не связаны с уменьшением размера UILabel?
Пример кода:
@implementation SOViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableAttributedString *text1 = [[NSMutableAttributedString alloc] init];
[text1 appendAttributedString:[[NSAttributedString alloc] initWithString:@"Line 1\n"]];
[text1 appendAttributedString:[[NSAttributedString alloc] initWithString:@"Line 2"]];
UIImage *image = [UIImage imageNamed:@"17x10"]; //some PNG image (17px by 10px)
NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
attachment.image = image;
attachment.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
NSMutableAttributedString *text2 = [[NSMutableAttributedString alloc] init];
[text2 appendAttributedString:[[NSAttributedString alloc] initWithString:@"Line 1\n"]];
[text2 appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]];
[text2 appendAttributedString:[[NSAttributedString alloc] initWithString:@"Line 2"]];
CGFloat margin = 20;
//shows both lines when height == 80
//shows line 2 when 90 <= height <= 120
//shows nothing when height == 130
CGFloat height = ???;
CGFloat width = 200;
UILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(margin, margin, width, height)];
UILabel *label2 = [[UILabel alloc] initWithFrame:CGRectMake(margin, margin + height, width, height)];
[self.view addSubview:label1];
[self.view addSubview:label2];
label1.backgroundColor = [UIColor orangeColor];
label2.backgroundColor = [UIColor blueColor];
label2.textColor = [UIColor whiteColor];
label1.numberOfLines = 0;
label2.numberOfLines = 0;
label1.attributedText = text1;
label2.attributedText = text2;
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(margin + width, margin + height, image.size.width, image.size.height);
[self.view addSubview:imageView];
}
@end
... Поместите это в контроллер представления по умолчанию для приложения "Single View". (Вы можете выбрать свое собственное изображение.)
Ответы
Ответ 1
Это не имеет ничего общего с NSTextAttachment. Это то, что в iOS 7, выпущенном до сих пор, UILabel не очень хорошо рисует атрибутивные строки. Простая атрибутная строка с некоторым подчеркиванием и центрированным стилем абзаца будет отображаться пустым или частично пустым в UILabel; эта же атрибутная строка отлично рисует в UITextView.
Итак, на данный момент существует одно решение: вместо этого используйте UITextView. Это на самом деле довольно хорошее решение, потому что в iOS 7 UITextView - это всего лишь обертка вокруг стека Text Kit. Таким образом, он нарисовал присланную строку простым способом. Это не мешает отношениям под капотом с Web Kit, которые были в предыдущих версиях iOS.
С другой стороны, я также нашел обходное решение для этой ошибки UILabel; вам нужно возиться с количеством строк метки и строки таким образом, чтобы замять текст до верхней части метки: см. мой ответ здесь - fooobar.com/questions/194697/...
Или вы можете просто ждать, пока Apple исправит ошибку и не скрежет пальцев. EDIT: в iOS 7.1, кажется, что ошибка будет исправлена и не потребуется обходной путь.
Ответ 2
Кажется, это ошибка в UILabel
. Тот же код отлично работает, когда UITextView
используется вместо UILabel
(UITextView
размер шрифта по умолчанию отличается, поэтому я тестировал его на разных высотах).
Ответ 3
Вы пытались получить фактическую высоту текста, используя метод boundingRectWithSize:
NSAttributedString *text;
CGFloat width = 200;
CGRect rect = [text boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading context:nil];
CGFloat height = rect.size.height;
Ответ 4
Я нашел другое обходное решение для этой ошибки, которое в значительной степени отличается от моего предыдущего ответа, что я предоставляю ему в качестве другого ответа: пусть метка устанавливает свою собственную высоту.
В этом коде я удаляю ограничение высоты с метки с ограничением фиксированной ширины и заменяя его ограничением по высоте (и я уверен, что есть другие способы достижения такого же результата):
[self.lab removeConstraint:self.labelHeight];
[self.lab addConstraint:
[NSLayoutConstraint constraintWithItem:self.lab
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationGreaterThanOrEqual
toItem:nil attribute:0 multiplier:1 constant:20]];
Эта метка правильно отображает каждую присланную строку, которую я бросаю на нее! Конечно, вы теряете автоматическое вертикальное центрирование строки, но весь источник ошибки, поэтому потерять ее не так страшно.