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.
import Mastodon
import SDWebImage
import UIKit
import ViewModels
@ -11,12 +12,21 @@ extension NSMutableAttributedString {
while let tokenRange = string.range(of: token) {
let attachment = AnimatedTextAttachment()
let imageURL: URL
if !identityContext.appPreferences.shouldReduceMotion,
identityContext.appPreferences.animateCustomEmojis {
attachment.imageURL = emoji.url
imageURL = emoji.url
} 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

View File

@ -22,10 +22,20 @@ final class AnimatedAttachmentLabel: UILabel, EmojiInsertable {
attributedText.enumerateAttribute(
.attachment,
in: NSRange(location: 0, length: attributedText.length)) { attachment, _, _ in
guard let attachmentImageView = (attachment as? AnimatedTextAttachment)?.imageView else { return }
in: NSRange(location: 0, length: attributedText.length),
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 {
@ -35,23 +45,5 @@ final class AnimatedAttachmentLabel: UILabel, EmojiInsertable {
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
final class AnimatedTextAttachment: NSTextAttachment {
var imageURL: URL?
var imageView = SDAnimatedImageView()
var imageBounds: CGRect?
let imageView = SDAnimatedImageView()
private(set) var imageBounds: CGRect?
override func image(forBounds imageBounds: CGRect,
textContainer: NSTextContainer?,
characterIndex charIndex: Int) -> UIImage? {
if let textContainer = textContainer,
let layoutManager = textContainer.layoutManager,
let textContainerImageBounds = textContainer.layoutManager?.boundingRect(
forGlyphRange: NSRange(location: charIndex, length: 1),
forGlyphRange: NSRange(location: layoutManager.glyphIndexForCharacter(at: charIndex), length: 1),
in: textContainer),
textContainerImageBounds != .zero {
self.imageBounds = textContainerImageBounds
} else {
// Labels sometimes, but not always, end up in this path
self.imageBounds = imageBounds
}

View File

@ -18,9 +18,18 @@ final class AnimatingLayoutManager: NSLayoutManager {
textStorage.enumerateAttribute(
.attachment,
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 ?? [] {
@ -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)
}
}