Animated UIImage in UITextView with TextKit

2019-02-11 20:46发布

问题:

I have a UIImage that contains multiple image frames and a duration which was sliced together from an animated GIF file. If I load the image in a UIWebView it will animate as expected, but I want to use a UITextView instead. The obvious choice is to use TextKit with a custom NSLayoutManger and many custom NSAttributedString attributes to achieve various drawing effects. I have a single UITextView that I'd like to give a NSAttributedString that contains NSTextAttachments for all of the images I need to display inline. It's working fine except for when I load one of these animated UIImages, they do not animate through their frames. Any thoughts on how to accomplish this? I've come up with a theoretical option:

  1. For each animated image add a custom defined attribute
  2. When layout manager goes to draw backgrounds, iterate this attribute to locate the positions of the attachment.
  3. Callback to the text view to create UIImageViews with the animated image, add as a subview, and call startAnimating

I have yet to try this, but it's fairly hacky. I'm wondering if there's a better option.

In summary: I want to animate a UIImage inside a UITextView via NSTextAttachment inside a NSAttributedString without the necessity for extra UIImageView objects. You can ignore the fact that this was previously done with a UIWebView. UIImage has properties (images, duration) for setting up animated frames, which I currently have configured. If I assign it to a UIImageView it animates, if I set it as a NSTextAttachment, no animation.

I would appreciate any feedback. Thanks!

回答1:

I think this behaviour is because the UITextView doesn't display the attachments using UIImageView subviews. When I observe the view hierarchy with and without the NSTextAttachments added to the UITextView, I don't see any new views (you can observe the view hierarchy using View Debugging in Xcode, or by saying [[[UIApplication sharedApplication] keyWindow] recursiveDescription]). Presumably, the UITextView just draws it's attachments directly.

That said, one way I can think of to include an animatable attachment is to create an animated UIImageView yourself as a subview of the UITextView, place it exactly where the NSLayoutManager places the NSTextAttachment, and scroll it whenever the UITextView scrolls. You can get the rectangle of the NSTextAttachment from the NSLayoutManager by calling boundingRectForGlyphRange:inTextContainer: (possibly in layoutManager:didCompleteLayoutForTextContainer:atEnd:).