You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS中如何设置自定义NSTextAttachmentViewProvider视图的尺寸?

解决UITextView中自定义NSTextAttachmentViewProvider无法设置尺寸的问题

在iOS15+中使用NSTextAttachmentViewProvider在UITextView中嵌入自定义UIView时,直接设置NSTextAttachment.bounds会导致自定义视图无法渲染,转而显示默认的缺失图片占位符。默认自定义视图尺寸为37x48,修改尺寸时出现异常。

问题原因

直接设置NSTextAttachment.bounds会让系统判定该附件为图像类型附件,优先尝试用bounds渲染图像占位,而非调用你注册的自定义NSTextAttachmentViewProvider加载视图。这是系统的优先级逻辑:当attachment存在bounds或image时,会优先走图像渲染路径,忽略自定义视图提供者。

解决方案

不要直接修改NSTextAttachment.bounds,而是通过自定义NSTextAttachment子类传递尺寸参数,在NSTextAttachmentViewProvider中根据参数设置视图尺寸;或者直接在Provider内部固定/动态设置视图约束。

方案1:自定义Attachment传递尺寸

  1. 创建自定义NSTextAttachment子类,添加尺寸属性:
@interface MyTextAttachment : NSTextAttachment
@property (nonatomic, assign) CGSize customSize;
@end

@implementation MyTextAttachment
@end
  1. 修改MyViewProvider,在loadView中根据attachment的customSize设置视图尺寸:
@implementation MyViewProvider

- (void)loadView {
    self.view = [UIView new];
    self.view.backgroundColor = [UIColor blueColor];
    
    // 从自定义Attachment获取尺寸
    MyTextAttachment *attachment = (MyTextAttachment *)self.attachment;
    if (!CGSizeEqualToSize(attachment.customSize, CGSizeZero)) {
        // 使用AutoLayout约束更适配文本排版
        [self.view.widthAnchor constraintEqualToConstant:attachment.customSize.width].active = YES;
        [self.view.heightAnchor constraintEqualToConstant:attachment.customSize.height].active = YES;
    }
}

@end
  1. 在ViewController中使用自定义Attachment:
- (void)viewDidLoad {
    [super viewDidLoad];

    [NSTextAttachment registerTextAttachmentViewProviderClass:[MyViewProvider class] forFileType:@"public.data"];

    MyTextAttachment *firstAttachment = [[MyTextAttachment alloc] initWithData:nil ofType:@"public.data"];
    // 不设置尺寸,使用默认
    MyTextAttachment *secondAttachment = [[MyTextAttachment alloc] initWithData:nil ofType:@"public.data"];
    secondAttachment.customSize = CGSizeMake(20, 20); // 传递自定义尺寸

    NSMutableAttributedString *string = [NSMutableAttributedString new];
    [string appendAttributedString:[[NSAttributedString alloc] initWithString:@"This is the 1st attachment: "]];
    [string appendAttributedString:[NSAttributedString attributedStringWithAttachment:firstAttachment]];

    [string appendAttributedString:[[NSAttributedString alloc] initWithString:@"\nThis is the 2nd attachment: "]];
    [string appendAttributedString:[NSAttributedString attributedStringWithAttachment:secondAttachment]];

    _textView = [UITextView new];
    _textView.layer.borderColor = [UIColor redColor].CGColor;
    _textView.layer.borderWidth = 1.0;
    _textView.attributedText = string;
    [self.view addSubview:_textView];
}

方案2:直接在Provider中固定尺寸(适合不需要动态调整的场景)

如果不需要动态传递尺寸,直接在MyViewProvider的loadView里设置视图约束:

@implementation MyViewProvider

- (void)loadView {
    self.view = [UIView new];
    self.view.backgroundColor = [UIColor blueColor];
    
    // 直接设置固定尺寸约束
    [self.view.widthAnchor constraintEqualToConstant:20].active = YES;
    [self.view.heightAnchor constraintEqualToConstant:20].active = YES;
}

@end

关键注意点

  • 避免直接修改NSTextAttachment.bounds,这会触发系统的图像渲染逻辑,绕过自定义视图提供者。
  • 使用AutoLayout约束比直接设置frame更可靠,尤其是在UITextView的排版环境中。
  • 确保注册的fileType和Attachment初始化时的ofType一致,否则系统找不到对应的视图提供者。

内容的提问来源于stack exchange,提问作者martega

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 05:46:42