【问题标题】:UITextView NSAttributedString SizeUITextView NSAttributedString 大小
【发布时间】:2013-01-10 18:59:57
【问题描述】:

我正在开发一个使用 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 的布局计算配合使用。

Here is example project which demonstrates the issue.

欢迎提出任何想法!

编辑:我还应该指出以下内容也不起作用:

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

【问题讨论】:

  • 对于一个普通的文本字符串,我把它放在一个虚拟标签中,缩小标签以适应,然后获取它的尺寸。

标签: ios objective-c uikit uitextview nsattributedstring


【解决方案1】:

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

- (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;
}

【讨论】:

  • 请检查self是否有非空文本,然后才使用firstCharacterOrigin的实现,如果没有,请添加return CGPointZero。看到这个stackoverflow.com/a/18548958/598057
【解决方案2】:

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

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

  • 将您的文本视图类更改为UILabel
  • 在标签上使用-setAttributedText:
  • 设置label.numberOfLines = 0(多行)
  • 在标签的 superview 调用的 -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

【讨论】:

  • 虽然 UILabel 大小正确,但它不可编辑。显然,我可以在触地时切换 UITextView 的标签,但如果可能的话,除非绝对必要,否则我想避免这条路线。
  • 当然,但这需要同时使用 UILabel 和 UITextView,正如我所说,我不介意,但如果有只使用 UITextView 的解决方案,那就太好了。跨度>
  • 根据您的编辑,我认为我们在此处的不同页面上。我不希望 textView 是视图的大小,它应该是适合文本所需的大小,不能大也不能小。
  • 这正是它所做的......它适合宽度,但高度会增长/收缩。试试我的代码。
  • 对,您的代码确实适合视图的宽度,这不是所需的行为,它应该足够大(宽度和高度)以适合文本,没有更多也没有少。
【解决方案3】:

上述汤姆欧文斯解决方案的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

    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-29
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多