mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-25 01:31:02 +00:00
Fix animated text attachment positioning
This commit is contained in:
parent
6f77983d8d
commit
f4e9f26df4
4 changed files with 41 additions and 47 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue