FLAnimatedImageView.swift 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. //
  2. // FLAnimatedImageView.swift
  3. // Mastodon
  4. //
  5. // Created by MainasuK Cirno on 2021-7-21.
  6. //
  7. import Foundation
  8. import Combine
  9. import Alamofire
  10. import AlamofireImage
  11. import FLAnimatedImage
  12. import UIKit
  13. private enum FLAnimatedImageViewAssociatedKeys {
  14. static var activeAvatarRequestURL = "FLAnimatedImageViewAssociatedKeys.activeAvatarRequestURL"
  15. static var avatarRequestCancellable = "FLAnimatedImageViewAssociatedKeys.avatarRequestCancellable"
  16. }
  17. extension FLAnimatedImageView {
  18. var activeAvatarRequestURL: URL? {
  19. get {
  20. objc_getAssociatedObject(self, &FLAnimatedImageViewAssociatedKeys.activeAvatarRequestURL) as? URL
  21. }
  22. set {
  23. objc_setAssociatedObject(self, &FLAnimatedImageViewAssociatedKeys.activeAvatarRequestURL, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  24. }
  25. }
  26. var avatarRequestCancellable: AnyCancellable? {
  27. get {
  28. objc_getAssociatedObject(self, &FLAnimatedImageViewAssociatedKeys.avatarRequestCancellable) as? AnyCancellable
  29. }
  30. set {
  31. objc_setAssociatedObject(self, &FLAnimatedImageViewAssociatedKeys.avatarRequestCancellable, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
  32. }
  33. }
  34. func setImage(
  35. url: URL?,
  36. placeholder: UIImage?,
  37. scaleToSize: CGSize?,
  38. completion: ((UIImage?) -> Void)? = nil
  39. ) {
  40. // cancel task
  41. activeAvatarRequestURL = nil
  42. avatarRequestCancellable?.cancel()
  43. // set placeholder
  44. image = placeholder
  45. // set image
  46. guard let url = url else { return }
  47. activeAvatarRequestURL = url
  48. let avatarRequest = AF.request(url).publishData()
  49. avatarRequestCancellable = avatarRequest
  50. .sink { response in
  51. switch response.result {
  52. case .success(let data):
  53. DispatchQueue.global().async {
  54. let image: UIImage? = {
  55. if let scaleToSize = scaleToSize {
  56. return UIImage(data: data)?.af.imageScaled(to: scaleToSize, scale: UIScreen.main.scale)
  57. } else {
  58. return UIImage(data: data)
  59. }
  60. }()
  61. let animatedImage = FLAnimatedImage(animatedGIFData: data)
  62. DispatchQueue.main.async { [weak self] in
  63. guard let self = self else { return }
  64. guard self.activeAvatarRequestURL == url else { return }
  65. if let animatedImage = animatedImage {
  66. self.animatedImage = animatedImage
  67. } else {
  68. self.image = image
  69. }
  70. completion?(image)
  71. }
  72. }
  73. case .failure:
  74. completion?(nil)
  75. }
  76. }
  77. }
  78. }