UITextView NSAttributedString Размер
Я работаю над приложением, которое использует UITextView.
UITextView должен увеличиваться или уменьшаться, чтобы соответствовать его тексту, как вертикально, так и горизонтально. Для этого я переопределяю sizeToFit в подклассе и устанавливаю границы следующим образом:
- (void)sizeToFit {
[self setBounds:(CGRect){.size = self.attributedText.size}];
}
Проблема в том, что этот размер просто не отражает правильный размер строки, поскольку UITextView обрезает текст. Я устанавливаю краевые вставки на ноль, так что это не должно быть проблемой, верно?
На данный момент, я думаю, что это ошибка со свойством размера NSAttributedString, но то же самое происходит, если я использую boundingRectWithSize:options:context:
[self setBounds:(CGRect){.size = [self.attributedText boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:0 context:nil].size}];
Поэтому, возможно, какой бы код ни выполнял вычисления макета для NSAttributedString, он не очень хорошо сочетается с вычислениями макета UITextView.
Вот пример проекта, который демонстрирует проблему.
Любые идеи приветствуются!
РЕДАКТИРОВАТЬ: Я также должен отметить, что следующее не работает либо:
- (void)sizeToFit {
[self setBounds:(CGRect){.size = [self sizeThatFits:self.attributedText.size]}];
}
3 ответа
Хотя и не идеально, я в конечном итоге использовал:
- (void)sizeToFit {
CGSize textSize = self.attributedText.size;
CGSize viewSize = CGSizeMake(textSize.width + self.firstCharacterOrigin.x * 2,
textSize.height + self.firstCharacterOrigin.y * 2);
[self setBounds:(CGRect){.size = [self sizeThatFits:viewSize]}];
}
- (CGPoint)firstCharacterOrigin {
if (!self.text.length) return CGPointZero;
UITextRange * range = [self textRangeFromPosition:[self positionFromPosition:self.beginningOfDocument offset:0]
toPosition:[self positionFromPosition:self.beginningOfDocument offset:1]];
return [self firstRectForRange:range].origin;
}
Я думаю, что вы правы - я не мог получить -[NSAttributedString boundingRectWithSize:options:context: ]
вернуть значение, которое работало правильно для всех размеров шрифта...
Тем не менее я получил UILabel для правильного размера и нарисовал приписанные строки:
- измените свой класс текстового представления на
UILabel
- использование
-setAttributedText:
на этикетке - задавать
label.numberOfLines = 0
(Многострочный) - в
-layoutSubviews
вызова superview вашей метки -[ label sizeThatFits: ], чтобы получить правильный размер для метки....
Работал на меня...
РЕДАКТИРОВАТЬ: Вот мой файл ViewController.m:
@interface View : UIView
@property ( nonatomic, strong ) UITextView * textView ;
@property ( nonatomic, strong ) UISlider * fontSizeSlider ;
@end
@implementation View
-(void)layoutSubviews
{
CGRect bounds = self.bounds ;
self.textView.layer.anchorPoint = (CGPoint){ 0.0f, 0.5f } ;
self.textView.layer.position = (CGPoint){ CGRectGetMinX( bounds ), CGRectGetMidY( bounds ) } ;
self.textView.bounds = (CGRect){ .size = [ self.textView sizeThatFits:bounds.size ] } ;
self.fontSizeSlider.frame = CGRectMake(5, CGRectGetMaxY(bounds) - 30, bounds.size.width - 10, 25) ;
}
@end
@interface ViewController ()
@end
@implementation ViewController
-(void)loadView
{
self.view = [[ View alloc ] initWithFrame:CGRectZero ] ;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableAttributedString * aString = [[ NSMutableAttributedString alloc ] initWithString:@"Some test text in a scaling text view" ] ;
NSDictionary * attributes = @{ NSForegroundColorAttributeName : [ UIColor redColor ] } ;
[ aString setAttributes:attributes range:(NSRange){ 5, 4 } ] ;
textView = [[UITextView alloc] initWithFrame:CGRectZero];
[textView setAttributedText:aString ];
[textView setFont:[UIFont systemFontOfSize:18]];
[textView setCenter:CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds))];
((View*)self.view).textView = textView ;
[self.view addSubview:textView];
[textView release];
UISlider * fontSizeSlider = [[UISlider alloc] initWithFrame:CGRectMake(5, CGRectGetMaxY(self.view.bounds) - 30, self.view.bounds.size.width - 10, 25)];
[fontSizeSlider addTarget:self action:@selector(fontSizeSliderDidChange:) forControlEvents:UIControlEventValueChanged];
[fontSizeSlider setMinimumValue:5];
[fontSizeSlider setMaximumValue:100];
[fontSizeSlider setValue:textView.font.pointSize];
((View*)self.view).fontSizeSlider = fontSizeSlider ;
[self.view addSubview:fontSizeSlider];
[fontSizeSlider release];
}
- (void)fontSizeSliderDidChange:(UISlider *)sender {
[ textView setFont:[textView.font fontWithSize:sender.value]];
[ self.view setNeedsLayout ] ;
}
@end
Решение Swift 3 для решения Tom Irvings выше:
extension UITextView {
func sizeToFitAttributedString() {
let textSize = self.attributedText.size()
let viewSize = CGSize(width: textSize.width + self.firstCharacterOrigin.x * 2, height: textSize.height + self.firstCharacterOrigin.y * 2)
self.bounds.size = self.sizeThatFits(viewSize)
}
private var firstCharacterOrigin: CGPoint {
if self.text.lengthOfBytes(using: .utf8) == 0 {
return .zero
}
let range = self.textRange(from: self.position(from: self.beginningOfDocument, offset: 0)!,
to: self.position(from: self.beginningOfDocument, offset: 1)!)
return self.firstRect(for: range!).origin
}
}