9

我正在开发一个使用 UITextView 的应用程序。

UITextView 应该垂直和水平地增长或缩小以适应其文本。为此,我在子类中覆盖 sizeToFit,并设置如下边界:

- (void)sizeToFit {
    [self setBounds:(CGRect){.size = self.attributedText.size}];
}

问题是这个大小不能反映字符串的正确大小,因为 UITextView 会剪辑文本。我将边缘插图设置为零,所以这不应该是一个问题,对吧?

在这一点上,我认为这是 NSAttributedString 的 size 属性的错误,但如果我使用 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]}];
}
4

3 回答 3

4

虽然不完美,但我最终使用了:

- (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;
}
于 2013-07-17T21:46:59.763 回答
1

我认为你是对的——我无法-[NSAttributedString boundingRectWithSize:options:context: ]返回一个适用于所有字体大小的值......

但是,我确实得到了一个 UILabel 来正确调整大小并绘制属性字符串:

  • 将您的文本视图类更改为UILabel
  • -setAttributedText:在标签上使用
  • 设置label.numberOfLines = 0(多行)
  • -layoutSubviews标签的超级视图调用中 -[ 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
于 2013-01-27T11:41:10.730 回答
0

上述汤姆·欧文斯解决方案的 swift 3 解决方案:

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

    }
}
于 2017-01-22T22:52:27.480 回答