SDWebImageSwiftUI/SDWebImageSwiftUI/Classes/ImageViewWrapper.swift

143 lines
4.8 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* This file is part of the SDWebImage package.
* (c) DreamPiggy <lizhuoli1126@126.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import Foundation
import SDWebImage
#if os(iOS) || os(tvOS) || os(macOS)
/// Use wrapper to solve tne `UIImageView`/`NSImageView` frame size become image size issue (SwiftUI's Bug)
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public class AnimatedImageViewWrapper : PlatformView {
var wrapped = SDAnimatedImageView()
var interpolationQuality = CGInterpolationQuality.default
var shouldAntialias = false
var resizable = false
override public func draw(_ rect: CGRect) {
#if os(macOS)
guard let ctx = NSGraphicsContext.current?.cgContext else {
return
}
#else
guard let ctx = UIGraphicsGetCurrentContext() else {
return
}
#endif
ctx.interpolationQuality = interpolationQuality
ctx.setShouldAntialias(shouldAntialias)
}
#if os(macOS)
public override func layout() {
super.layout()
wrapped.frame = self.bounds
}
#else
public override func layoutSubviews() {
super.layoutSubviews()
wrapped.frame = self.bounds
}
#endif
public override var intrinsicContentSize: CGSize {
/// Match the behavior of SwiftUI.Image, only when image is resizable, use the super implementation to calculate size
if resizable {
return super.intrinsicContentSize
} else {
/// Not resizable, always use image size, like SwiftUI.Image
return wrapped.intrinsicContentSize
}
}
public override init(frame frameRect: CGRect) {
super.init(frame: frameRect)
addSubview(wrapped)
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
addSubview(wrapped)
}
}
/// Store the Animated Image loading state, to avoid re-query duinrg `updateView(_:)` until Source of Truth changes
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension PlatformView {
static private var sd_imageNameKey: Void?
static private var sd_imageDataKey: Void?
var sd_imageName: String? {
get {
objc_getAssociatedObject(self, &PlatformView.sd_imageNameKey) as? String
}
set {
objc_setAssociatedObject(self, &PlatformView.sd_imageNameKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
var sd_imageData: Data? {
get {
objc_getAssociatedObject(self, &PlatformView.sd_imageDataKey) as? Data
}
set {
objc_setAssociatedObject(self, &PlatformView.sd_imageDataKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}
/// Use wrapper to solve the `UIProgressView`/`NSProgressIndicator` frame origin NaN crash (SwiftUI's bug)
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public class ProgressIndicatorWrapper : PlatformView {
#if os(macOS)
var wrapped = NSProgressIndicator()
#else
var wrapped = UIProgressView(progressViewStyle: .default)
#endif
#if os(macOS)
public override func layout() {
super.layout()
wrapped.setFrameOrigin(CGPoint(x: round(self.bounds.width - wrapped.frame.width) / 2, y: round(self.bounds.height - wrapped.frame.height) / 2))
}
#else
public override func layoutSubviews() {
super.layoutSubviews()
wrapped.center = self.center
}
#endif
public override init(frame frameRect: CGRect) {
super.init(frame: frameRect)
addSubview(wrapped)
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
addSubview(wrapped)
}
}
extension PlatformView {
/// Adds constraints to this `UIView` instances `superview` object to make sure this always has the same size as the superview.
/// Please note that this has no effect if its `superview` is `nil` add this `UIView` instance as a subview before calling this.
func bindFrameToSuperviewBounds() {
guard let superview = self.superview else {
print("Error! `superview` was nil call `addSubview(view: UIView)` before calling `bindFrameToSuperviewBounds()` to fix this.")
return
}
self.translatesAutoresizingMaskIntoConstraints = false
self.topAnchor.constraint(equalTo: superview.topAnchor, constant: 0).isActive = true
self.bottomAnchor.constraint(equalTo: superview.bottomAnchor, constant: 0).isActive = true
self.leadingAnchor.constraint(equalTo: superview.leadingAnchor, constant: 0).isActive = true
self.trailingAnchor.constraint(equalTo: superview.trailingAnchor, constant: 0).isActive = true
}
}
#endif