diff --git a/SDWebImageSwiftUI.xcodeproj/project.pbxproj b/SDWebImageSwiftUI.xcodeproj/project.pbxproj index 916f00dc..3781f140 100644 --- a/SDWebImageSwiftUI.xcodeproj/project.pbxproj +++ b/SDWebImageSwiftUI.xcodeproj/project.pbxproj @@ -31,6 +31,14 @@ 326E480B23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; }; 326E480C23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; }; 326E480D23431C0F00C633E9 /* ImageViewWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */; }; + 3276EB00237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3276EAFE237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3276EB01237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3276EAFE237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3276EB02237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3276EAFE237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3276EB03237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h in Headers */ = {isa = PBXBuildFile; fileRef = 3276EAFE237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 3276EB04237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3276EAFF237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m */; }; + 3276EB05237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3276EAFF237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m */; }; + 3276EB06237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3276EAFF237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m */; }; + 3276EB07237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 3276EAFF237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m */; }; 32B933E523659A1900BB7CAD /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B933E423659A1900BB7CAD /* Transition.swift */; }; 32B933E623659A1900BB7CAD /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B933E423659A1900BB7CAD /* Transition.swift */; }; 32B933E723659A1900BB7CAD /* Transition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32B933E423659A1900BB7CAD /* Transition.swift */; }; @@ -119,6 +127,8 @@ 326B8486236335110011BDFB /* ActivityIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActivityIndicator.swift; sourceTree = ""; }; 326B848B236335400011BDFB /* ProgressIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressIndicator.swift; sourceTree = ""; }; 326E480923431C0F00C633E9 /* ImageViewWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewWrapper.swift; sourceTree = ""; }; + 3276EAFE237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDAnimatedImageInterfaceWrapper.h; sourceTree = ""; }; + 3276EAFF237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDAnimatedImageInterfaceWrapper.m; sourceTree = ""; }; 32B933E423659A1900BB7CAD /* Transition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Transition.swift; sourceTree = ""; }; 32C43DCC22FD540D00BE87F5 /* SDWebImageSwiftUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SDWebImageSwiftUI.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 32C43DDC22FD54C600BE87F5 /* ImageManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageManager.swift; sourceTree = ""; }; @@ -177,6 +187,8 @@ children = ( 324F61C5235E07EC003973B8 /* SDAnimatedImageInterface.h */, 324F61C6235E07EC003973B8 /* SDAnimatedImageInterface.m */, + 3276EAFE237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h */, + 3276EAFF237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m */, ); path = ObjC; sourceTree = ""; @@ -262,6 +274,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 3276EB00237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h in Headers */, 324F61C7235E07EC003973B8 /* SDAnimatedImageInterface.h in Headers */, 32C43DE622FD54CD00BE87F5 /* SDWebImageSwiftUI.h in Headers */, ); @@ -271,6 +284,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 3276EB01237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h in Headers */, 324F61C8235E07EC003973B8 /* SDAnimatedImageInterface.h in Headers */, 32C43E2222FD583A00BE87F5 /* SDWebImageSwiftUI.h in Headers */, ); @@ -280,6 +294,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 3276EB02237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h in Headers */, 324F61C9235E07EC003973B8 /* SDAnimatedImageInterface.h in Headers */, 32C43E2322FD583B00BE87F5 /* SDWebImageSwiftUI.h in Headers */, ); @@ -289,6 +304,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 3276EB03237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.h in Headers */, 324F61CA235E07EC003973B8 /* SDAnimatedImageInterface.h in Headers */, 32C43E2422FD583C00BE87F5 /* SDWebImageSwiftUI.h in Headers */, ); @@ -457,6 +473,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3276EB04237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m in Sources */, 32B933E523659A1900BB7CAD /* Transition.swift in Sources */, 32C43E1722FD583700BE87F5 /* WebImage.swift in Sources */, 326B848C236335400011BDFB /* ProgressIndicator.swift in Sources */, @@ -474,6 +491,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3276EB05237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m in Sources */, 32B933E623659A1900BB7CAD /* Transition.swift in Sources */, 32C43E1A22FD583700BE87F5 /* WebImage.swift in Sources */, 326B848D236335400011BDFB /* ProgressIndicator.swift in Sources */, @@ -491,6 +509,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3276EB06237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m in Sources */, 32B933E723659A1900BB7CAD /* Transition.swift in Sources */, 32C43E1D22FD583800BE87F5 /* WebImage.swift in Sources */, 326B848E236335400011BDFB /* ProgressIndicator.swift in Sources */, @@ -508,6 +527,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3276EB07237760D800B385D4 /* SDAnimatedImageInterfaceWrapper.m in Sources */, 32B933E823659A1900BB7CAD /* Transition.swift in Sources */, 32C43E2022FD583800BE87F5 /* WebImage.swift in Sources */, 326B848F236335400011BDFB /* ProgressIndicator.swift in Sources */, diff --git a/SDWebImageSwiftUI/Classes/AnimatedImage.swift b/SDWebImageSwiftUI/Classes/AnimatedImage.swift index 7a55f3bb..2295b337 100644 --- a/SDWebImageSwiftUI/Classes/AnimatedImage.swift +++ b/SDWebImageSwiftUI/Classes/AnimatedImage.swift @@ -14,12 +14,7 @@ import SDWebImageSwiftUIObjC // Convenient #if os(watchOS) -public typealias AnimatedImageViewWrapper = SDAnimatedImageInterface -extension SDAnimatedImageInterface { - var wrapped: SDAnimatedImageInterface { - return self - } -} +public typealias AnimatedImageViewWrapper = SDAnimatedImageInterfaceWrapper #endif // Coordinator Life Cycle Binding Object @@ -122,7 +117,7 @@ public struct AnimatedImage : PlatformViewRepresentable { #else let image = SDAnimatedImage(named: name, in: bundle, compatibleWith: nil) #endif - self.image = image + _image = .init(wrappedValue: image) } /// Create an animated image with data and scale. @@ -139,7 +134,7 @@ public struct AnimatedImage : PlatformViewRepresentable { public init(data: Data, scale: CGFloat = 0, isAnimating: Binding) { self._isAnimating = isAnimating let image = SDAnimatedImage(data: data, scale: scale) - self.image = image + _image = .init(wrappedValue: image) } #if os(macOS) @@ -432,6 +427,8 @@ public struct AnimatedImage : PlatformViewRepresentable { // Antialiased view.shouldAntialias = self.antialiased #endif + + view.invalidateIntrinsicContentSize() } func configureView(_ view: AnimatedImageViewWrapper, context: Context) { @@ -562,19 +559,7 @@ extension AnimatedImage { var result = self result.aspectRatio = aspectRatio result.contentMode = contentMode - #if os(macOS) || os(iOS) || os(tvOS) return result.modifier(EmptyModifier()).aspectRatio(aspectRatio, contentMode: contentMode) - #else - return Group { - if aspectRatio != nil { - result.modifier(EmptyModifier()).aspectRatio(aspectRatio, contentMode: contentMode) - } else { - // on watchOS, there are no workaround like `AnimatedImageViewWrapper` to override `intrinsicContentSize`, so the aspect ratio is undetermined and cause sizing issues - // To workaround, we do not call default implementation for this case, using original solution instead - result - } - } - #endif } /// Constrains this view's dimensions to the aspect ratio of the given size. diff --git a/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.h b/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.h index 3717a826..49d43bb2 100644 --- a/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.h +++ b/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.h @@ -12,6 +12,7 @@ NS_ASSUME_NONNULL_BEGIN /// Do not use this class directly in WatchKit or Storyboard. This class is implementation detail and will be removed in the future. +/// This is not public API at all. @interface SDAnimatedImageInterface : WKInterfaceImage @property (nonatomic, assign, getter=isAnimating, readonly) BOOL animating; diff --git a/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.m b/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.m index 60b08597..23c2e2c8 100644 --- a/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.m +++ b/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterface.m @@ -11,24 +11,6 @@ #pragma mark - SPI -static UIImage * SharedEmptyImage(void) { - // This is used for placeholder on `WKInterfaceImage` - // Do not using `[UIImage new]` because WatchKit will ignore it - static dispatch_once_t onceToken; - static UIImage *image; - dispatch_once(&onceToken, ^{ - UIColor *color = UIColor.clearColor; - CGRect rect = WKInterfaceDevice.currentDevice.screenBounds; - UIGraphicsBeginImageContext(rect.size); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [color CGColor]); - CGContextFillRect(context, rect); - image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - }); - return image; -} - @protocol CALayerProtocol @property (nullable, strong) id contents; @property CGFloat contentsScale; @@ -43,6 +25,16 @@ @protocol UIViewProtocol @property (nonatomic) CGFloat alpha; @property (nonatomic, getter=isHidden) BOOL hidden; @property (nonatomic, getter=isOpaque) BOOL opaque; +@property (nonatomic) CGRect frame; +@property (nonatomic) CGRect bounds; +@property (nonatomic) CGPoint center; +@property (nonatomic, readonly) CGSize intrinsicContentSize; +@property(nonatomic) NSInteger tag; + +- (void)invalidateIntrinsicContentSize; +- (void)layoutSubviews; +- (CGSize)sizeThatFits:(CGSize)size; +- (void)sizeToFit; @end @@ -59,8 +51,9 @@ @interface WKInterfaceObject () // This is needed for dynamic created WKInterfaceObject, like `WKInterfaceMap` - (instancetype)_initForDynamicCreationWithInterfaceProperty:(NSString *)property; +- (NSDictionary *)interfaceDescriptionForDynamicCreation; // This is remote UIView -@property (nonatomic, strong, readonly) id _interfaceView; +@property (nonatomic, strong, readwrite) id _interfaceView; @end @@ -97,7 +90,6 @@ - (NSDictionary *)interfaceDescriptionForDynamicCreation { return @{ @"type" : @"image", @"property" : self.interfaceProperty, - @"image" : SharedEmptyImage() }; } @@ -113,8 +105,7 @@ - (void)setImage:(UIImage *)image { self.currentFrameIndex = 0; self.currentLoopCount = 0; - [super setImage:image]; - [self _interfaceView].image = image; + ((id)[self _interfaceView]).image = image; if ([image.class conformsToProtocol:@protocol(SDAnimatedImage)]) { // Create animted player self.player = [SDAnimatedImagePlayer playerWithProvider:(id)image]; @@ -258,4 +249,5 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url } @end + #endif diff --git a/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterfaceWrapper.h b/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterfaceWrapper.h new file mode 100644 index 00000000..eb24e2cd --- /dev/null +++ b/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterfaceWrapper.h @@ -0,0 +1,27 @@ +/* +* This file is part of the SDWebImage package. +* (c) DreamPiggy +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +#import "SDAnimatedImageInterface.h" + +#if SD_WATCH +NS_ASSUME_NONNULL_BEGIN + +/// Do not use this class directly in WatchKit or Storyboard. This class is implementation detail and will be removed in the future. +/// This is not public API at all. +@interface SDAnimatedImageInterfaceWrapper : WKInterfaceGroup + +@property (nonatomic, strong, nonnull) SDAnimatedImageInterface *wrapped; + +- (instancetype)init WK_AVAILABLE_WATCHOS_ONLY(6.0); + +- (void)invalidateIntrinsicContentSize; + +@end + +NS_ASSUME_NONNULL_END +#endif diff --git a/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterfaceWrapper.m b/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterfaceWrapper.m new file mode 100644 index 00000000..40ea7841 --- /dev/null +++ b/SDWebImageSwiftUI/Classes/ObjC/SDAnimatedImageInterfaceWrapper.m @@ -0,0 +1,203 @@ +/* +* This file is part of the SDWebImage package. +* (c) DreamPiggy +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +#import "SDAnimatedImageInterfaceWrapper.h" +#if SD_WATCH +#import +#import + +#pragma mark - SPI + +@protocol CALayerProtocol +@property (nullable, strong) id contents; +@property CGFloat contentsScale; +@end + +@protocol UIViewProtocol +@property (nonatomic, strong, readonly) id layer; +@property (nonatomic, assign) SDImageScaleMode contentMode; +@property (nonatomic, readonly) id superview; +@property (nonatomic, readonly, copy) NSArray> *subviews; +@property (nonatomic, readonly) id window; +@property (nonatomic) CGFloat alpha; +@property (nonatomic, getter=isHidden) BOOL hidden; +@property (nonatomic, getter=isOpaque) BOOL opaque; +@property (nonatomic) CGRect frame; +@property (nonatomic) CGRect bounds; +@property (nonatomic) CGPoint center; +@property (nonatomic, readonly) CGSize intrinsicContentSize; +@property(nonatomic) NSInteger tag; + +- (void)invalidateIntrinsicContentSize; +- (void)layoutSubviews; +- (CGSize)sizeThatFits:(CGSize)size; +- (void)sizeToFit; + +@end + +@protocol UIImageViewProtocol + +@property (nullable, nonatomic, strong) UIImage *image; +- (void)startAnimating; +- (void)stopAnimating; +@property (nonatomic, readonly, getter=isAnimating) BOOL animating; + +@end + +@interface WKInterfaceObject () + +// This is needed for dynamic created WKInterfaceObject, like `WKInterfaceMap` +- (instancetype)_initForDynamicCreationWithInterfaceProperty:(NSString *)property; +- (NSDictionary *)interfaceDescriptionForDynamicCreation; +// This is remote UIView +@property (nonatomic, strong, readwrite) id _interfaceView; + +@end + +#define SDAnimatedImageInterfaceWrapperTag 123456789 +#define SDAnimatedImageInterfaceWrapperSEL_layoutSubviews @"SDAnimatedImageInterfaceWrapper_layoutSubviews" +#define SDAnimatedImageInterfaceWrapperSEL_sizeThatFits @" SDAnimatedImageInterfaceWrapper_sizeThatFits:" + +// This using hook to implements the same logic like AnimatedImageViewWrapper.swift +static CGSize intrinsicContentSizeIMP(id self, SEL _cmd) { + struct objc_super superClass = { + self, + [self superclass] + }; + NSUInteger tag = self.tag; + id interfaceView = self.subviews.firstObject; + if (tag != SDAnimatedImageInterfaceWrapperTag || !interfaceView) { + return ((CGSize(*)(id, SEL))objc_msgSendSuper)((__bridge id)(&superClass), _cmd); + } + CGSize size = interfaceView.intrinsicContentSize; + if (size.width > 0 && size.height > 0) { + CGFloat aspectRatio = size.height / size.width; + return CGSizeMake(1, 1 * aspectRatio); + } else { + return CGSizeMake(-1, -1); + } +} + +static void layoutSubviewsIMP(id self, SEL _cmd) { + struct objc_super superClass = { + self, + [self superclass] + }; + NSUInteger tag = self.tag; + id interfaceView = self.subviews.firstObject; + if (tag != SDAnimatedImageInterfaceWrapperTag || !interfaceView) { + ((void(*)(id, SEL))objc_msgSend)(self, NSSelectorFromString(SDAnimatedImageInterfaceWrapperSEL_layoutSubviews)); + return; + } + ((void(*)(id, SEL))objc_msgSendSuper)((__bridge id)(&superClass), _cmd); + interfaceView.frame = self.bounds; +} + +// This is suck that SwiftUI on watchOS will call extra sizeThatFits, we should always return input size (already calculated with aspectRatio) +// iOS's wrapper don't need this. Apple should provide the public API on View protocol to specify `intrinsicContentSize` or `intrinsicAspectRatio` +static CGSize sizeThatFitsIMP(id self, SEL _cmd, CGSize size) { + NSUInteger tag = self.tag; + id interfaceView = self.subviews.firstObject; + if (tag != SDAnimatedImageInterfaceWrapperTag || !interfaceView) { + return ((CGSize(*)(id, SEL))objc_msgSend)(self, NSSelectorFromString(SDAnimatedImageInterfaceWrapperSEL_sizeThatFits)); + } + return size; +} + +@implementation SDAnimatedImageInterfaceWrapper + +/// Use wrapper to solve tne watchOS `WKInterfaceImage` frame size become image size issue, as well as aspect ratio issue (SwiftUI's Bug) ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Class class = NSClassFromString(@"SPInterfaceGroupView"); + // Implements `intrinsicContentSize` + SEL selector = @selector(intrinsicContentSize); + Method method = class_getInstanceMethod(class, selector); + + BOOL didAddMethod = + class_addMethod(class, + selector, + (IMP)intrinsicContentSizeIMP, + method_getTypeEncoding(method)); + if (!didAddMethod) { + NSAssert(NO, @"SDAnimatedImageInterfaceWrapper will not work as expected."); + } + + // Override `layoutSubviews` + SEL originalSelector = @selector(layoutSubviews); + SEL swizzledSelector = NSSelectorFromString(SDAnimatedImageInterfaceWrapperSEL_layoutSubviews); + Method originalMethod = class_getInstanceMethod(class, originalSelector); + + didAddMethod = + class_addMethod(class, + swizzledSelector, + (IMP)layoutSubviewsIMP, + method_getTypeEncoding(originalMethod)); + if (!didAddMethod) { + NSAssert(NO, @"SDAnimatedImageInterfaceWrapper will not work as expected."); + } else { + Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); + method_exchangeImplementations(originalMethod, swizzledMethod); + } + + // Override `sizeThatFits:` + originalSelector = @selector(sizeThatFits:); + swizzledSelector = NSSelectorFromString(SDAnimatedImageInterfaceWrapperSEL_sizeThatFits); + originalMethod = class_getInstanceMethod(class, originalSelector); + + didAddMethod = + class_addMethod(class, + swizzledSelector, + (IMP)sizeThatFitsIMP, + method_getTypeEncoding(originalMethod)); + if (!didAddMethod) { + NSAssert(NO, @"SDAnimatedImageInterfaceWrapper will not work as expected."); + } else { + Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); + method_exchangeImplementations(originalMethod, swizzledMethod); + } + }); +} + +- (instancetype)init { + Class cls = [self class]; + NSString *UUID = [NSUUID UUID].UUIDString; + NSString *property = [NSString stringWithFormat:@"%@_%@", cls, UUID]; + self = [self _initForDynamicCreationWithInterfaceProperty:property]; + if (self) { + self.wrapped = [[SDAnimatedImageInterface alloc] init]; + } + return self; +} + +- (NSDictionary *)interfaceDescriptionForDynamicCreation { + // This is called by WatchKit to provide default value + return @{ + @"type" : @"group", + @"property" : self.interfaceProperty, + @"radius" : @(0), + @"items": @[self.wrapped.interfaceDescriptionForDynamicCreation], // This will create the native view and added to subview + }; +} + +- (void)set_interfaceView:(id)interfaceView { + // This is called by WatchKit when native view created + [super set_interfaceView:interfaceView]; + // Bind the interface object and native view + interfaceView.tag = SDAnimatedImageInterfaceWrapperTag; + self.wrapped._interfaceView = interfaceView.subviews.firstObject; +} + +- (void)invalidateIntrinsicContentSize { + [self._interfaceView invalidateIntrinsicContentSize]; +} + +@end + +#endif diff --git a/SDWebImageSwiftUI/Module/SDWebImageSwiftUI.h b/SDWebImageSwiftUI/Module/SDWebImageSwiftUI.h index 958fe3ec..4fc701b2 100644 --- a/SDWebImageSwiftUI/Module/SDWebImageSwiftUI.h +++ b/SDWebImageSwiftUI/Module/SDWebImageSwiftUI.h @@ -8,6 +8,7 @@ #import #import +#import //! Project version number for SDWebImageSwiftUI. FOUNDATION_EXPORT double SDWebImageSwiftUIVersionNumber;