tracksTextAttachmentViewBounds not working

Hello :),

I want to have a UIView inside of a UITextView. For that I use the new NSTextAttachmentViewProvider class introduced in iOS 15. The views width should always be equal to the width of the UITextView this width should update when, for example, the screen rotates.

To do that I am using the tracksTextAttachmentViewBounds property inside of a NSTextAttachmentViewProvider subclass. If I understand correctly, if this property is set to true, the function attachmentBounds(for:location:textContainer:proposedLineFragment:position:) of my NSTextAttachmentViewProvider subclass should be used to determine the views bounds. In the code example below I have set it up in that manner, sadly the function is never called. (The storyboard consists of a UIViewController with a UITextView which four constrains (trailing, leading, bottom, top) are set equal to the safe area, nothing special going on). I have also tried to use a NSTextAttachment subclass in which I override the attachmentBounds(for:location:textContainer:proposedLineFragment:position:) function. It is also not called. The view is appearing, but not with the width and height that I have set in the function (see screenshot below), maybe it is using some default values. When I start typing, the view disappears.

I don't know what I am doing wrong. Could somebody help me with that problem?

import UIKit

class SomeNSTextAttachmentViewProvider : NSTextAttachmentViewProvider {
    override func loadView() {
        super.loadView()
        tracksTextAttachmentViewBounds = true
        view = UIView()
        view!.backgroundColor = .purple
    }

    override func attachmentBounds(
        for attributes: [NSAttributedString.Key : Any],
        location: NSTextLocation,
        textContainer: NSTextContainer?,
        proposedLineFragment: CGRect,
        position: CGPoint
    ) -> CGRect {
        return CGRect(x: 0, y: 0, width: proposedLineFragment.width, height: 200)
    }
}

class ViewController: UIViewController {
    @IBOutlet var textView: UITextView?

    override func viewDidLoad() {
        super.viewDidLoad()

        NSTextAttachment.registerViewProviderClass(SomeNSTextAttachmentViewProvider.self, forFileType: "public.data")

        let mutableAttributedString = NSMutableAttributedString()
        mutableAttributedString.append(NSAttributedString("purple box: "))
        mutableAttributedString.append(
            NSAttributedString(
                attachment: NSTextAttachment(data: nil, ofType: "public.data")
            )
        )
		textView?.attributedText = mutableAttributedString
        textView?.font = UIFont.preferredFont(forTextStyle: .body)
	}
}

Answered by Frameworks Engineer in 716633022

Hello,

With UITextView in iOS 16 supporting TextKit 2, your sample should work now. One thing to update here is that you should set tracksTextAttachmentViewBounds inside the initializer. NSTextAttachmentViewProvider.loadView() can be lazily invoked after the layout queried.

Accepted Answer

Hello,

With UITextView in iOS 16 supporting TextKit 2, your sample should work now. One thing to update here is that you should set tracksTextAttachmentViewBounds inside the initializer. NSTextAttachmentViewProvider.loadView() can be lazily invoked after the layout queried.

tracksTextAttachmentViewBounds not working
 
 
Q