Fix animated text attachment positioning

This commit is contained in:
Justin Mazzocchi 2021-02-22 18:51:31 -08:00
parent 6f77983d8d
commit f4e9f26df4
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
4 changed files with 41 additions and 47 deletions

View file

@ -1,6 +1,7 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import Mastodon import Mastodon
import SDWebImage
import UIKit import UIKit
import ViewModels import ViewModels
@ -11,12 +12,21 @@ extension NSMutableAttributedString {
while let tokenRange = string.range(of: token) { while let tokenRange = string.range(of: token) {
let attachment = AnimatedTextAttachment() let attachment = AnimatedTextAttachment()
let imageURL: URL
if !identityContext.appPreferences.shouldReduceMotion, if !identityContext.appPreferences.shouldReduceMotion,
identityContext.appPreferences.animateCustomEmojis { identityContext.appPreferences.animateCustomEmojis {
attachment.imageURL = emoji.url imageURL = emoji.url
} else { } else {
attachment.imageURL = emoji.staticUrl imageURL = emoji.staticUrl
}
attachment.imageView.sd_setImage(with: imageURL) { image, _, _, _ in
attachment.image = image
DispatchQueue.main.async {
view.setNeedsDisplay()
}
} }
attachment.accessibilityLabel = emoji.shortcode attachment.accessibilityLabel = emoji.shortcode

View file

@ -22,10 +22,20 @@ final class AnimatedAttachmentLabel: UILabel, EmojiInsertable {
attributedText.enumerateAttribute( attributedText.enumerateAttribute(
.attachment, .attachment,
in: NSRange(location: 0, length: attributedText.length)) { attachment, _, _ in in: NSRange(location: 0, length: attributedText.length),
guard let attachmentImageView = (attachment as? AnimatedTextAttachment)?.imageView else { return } options: .longestEffectiveRangeNotRequired) { attachment, _, _ in
guard let animatedAttachment = attachment as? AnimatedTextAttachment,
let imageBounds = animatedAttachment.imageBounds
else { return }
attachmentImageViews.insert(attachmentImageView) animatedAttachment.imageView.frame = imageBounds
animatedAttachment.imageView.contentMode = .scaleAspectFit
if animatedAttachment.imageView.superview != self {
addSubview(animatedAttachment.imageView)
}
attachmentImageViews.insert(animatedAttachment.imageView)
} }
for subview in subviews { for subview in subviews {
@ -35,23 +45,5 @@ final class AnimatedAttachmentLabel: UILabel, EmojiInsertable {
attachmentImageView.removeFromSuperview() attachmentImageView.removeFromSuperview()
} }
} }
attributedText.enumerateAttribute(
.attachment,
in: NSRange(location: 0, length: attributedText.length),
options: .longestEffectiveRangeNotRequired) { attachment, _, _ in
guard let animatedAttachment = attachment as? AnimatedTextAttachment,
let imageBounds = animatedAttachment.imageBounds
else { return }
animatedAttachment.imageView.frame = imageBounds
animatedAttachment.imageView.image = animatedAttachment.image
animatedAttachment.imageView.contentMode = .scaleAspectFit
animatedAttachment.imageView.sd_setImage(with: animatedAttachment.imageURL)
if animatedAttachment.imageView.superview != self {
addSubview(animatedAttachment.imageView)
}
}
} }
} }

View file

@ -4,20 +4,21 @@ import SDWebImage
import UIKit import UIKit
final class AnimatedTextAttachment: NSTextAttachment { final class AnimatedTextAttachment: NSTextAttachment {
var imageURL: URL? let imageView = SDAnimatedImageView()
var imageView = SDAnimatedImageView() private(set) var imageBounds: CGRect?
var imageBounds: CGRect?
override func image(forBounds imageBounds: CGRect, override func image(forBounds imageBounds: CGRect,
textContainer: NSTextContainer?, textContainer: NSTextContainer?,
characterIndex charIndex: Int) -> UIImage? { characterIndex charIndex: Int) -> UIImage? {
if let textContainer = textContainer, if let textContainer = textContainer,
let layoutManager = textContainer.layoutManager,
let textContainerImageBounds = textContainer.layoutManager?.boundingRect( let textContainerImageBounds = textContainer.layoutManager?.boundingRect(
forGlyphRange: NSRange(location: charIndex, length: 1), forGlyphRange: NSRange(location: layoutManager.glyphIndexForCharacter(at: charIndex), length: 1),
in: textContainer), in: textContainer),
textContainerImageBounds != .zero { textContainerImageBounds != .zero {
self.imageBounds = textContainerImageBounds self.imageBounds = textContainerImageBounds
} else { } else {
// Labels sometimes, but not always, end up in this path
self.imageBounds = imageBounds self.imageBounds = imageBounds
} }

View file

@ -18,9 +18,18 @@ final class AnimatingLayoutManager: NSLayoutManager {
textStorage.enumerateAttribute( textStorage.enumerateAttribute(
.attachment, .attachment,
in: NSRange(location: 0, length: textStorage.length)) { attachment, _, _ in in: NSRange(location: 0, length: textStorage.length)) { attachment, _, _ in
guard let attachmentImageView = (attachment as? AnimatedTextAttachment)?.imageView else { return } guard let animatedAttachment = attachment as? AnimatedTextAttachment,
let imageBounds = animatedAttachment.imageBounds
else { return }
attachmentImageViews.insert(attachmentImageView) animatedAttachment.imageView.frame = imageBounds
animatedAttachment.imageView.contentMode = .scaleAspectFit
if animatedAttachment.imageView.superview != view {
view?.addSubview(animatedAttachment.imageView)
}
attachmentImageViews.insert(animatedAttachment.imageView)
} }
for subview in view?.subviews ?? [] { for subview in view?.subviews ?? [] {
@ -31,24 +40,6 @@ final class AnimatingLayoutManager: NSLayoutManager {
} }
} }
textStorage.enumerateAttribute(
.attachment,
in: glyphsToShow,
options: .longestEffectiveRangeNotRequired) { attachment, range, _ in
guard let animatedAttachment = attachment as? AnimatedTextAttachment,
let textContainer = textContainer(forGlyphAt: range.location, effectiveRange: nil)
else { return }
animatedAttachment.imageView.frame = boundingRect(forGlyphRange: range, in: textContainer)
animatedAttachment.imageView.image = animatedAttachment.image
animatedAttachment.imageView.contentMode = .scaleAspectFit
animatedAttachment.imageView.sd_setImage(with: animatedAttachment.imageURL)
if animatedAttachment.imageView.superview != view {
view?.addSubview(animatedAttachment.imageView)
}
}
super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin) super.drawGlyphs(forGlyphRange: glyphsToShow, at: origin)
} }
} }