99#import " SDAnimatedImageInterface.h"
1010#if SD_WATCH
1111
12- #import < objc/runtime.h>
13- #import < objc/message.h>
14-
1512#pragma mark - SPI
1613
1714@protocol CALayerProtocol <NSObject >
@@ -31,16 +28,10 @@ @protocol UIViewProtocol <NSObject>
3128@property (nonatomic ) CGRect frame;
3229@property (nonatomic ) CGRect bounds;
3330@property (nonatomic ) CGPoint center;
34- @property (nonatomic ) BOOL clipsToBounds;
3531@property (nonatomic , readonly ) CGSize intrinsicContentSize;
3632@property (nonatomic ) NSInteger tag;
3733
3834- (void )invalidateIntrinsicContentSize ;
39- - (void )drawRect : (CGRect)rect ;
40- - (void )setNeedsDisplay ;
41- - (void )setNeedsDisplayInRect : (CGRect)rect ;
42- - (void )addSubview : (id <UIViewProtocol>)view ;
43- - (void )removeFromSuperview ;
4435- (void )layoutSubviews ;
4536- (CGSize)sizeThatFits : (CGSize)size ;
4637- (void )sizeToFit ;
@@ -60,6 +51,7 @@ @interface WKInterfaceObject ()
6051
6152// This is needed for dynamic created WKInterfaceObject, like `WKInterfaceMap`
6253- (instancetype )_initForDynamicCreationWithInterfaceProperty : (NSString *)property ;
54+ - (NSDictionary *)interfaceDescriptionForDynamicCreation ;
6355// This is remote UIView
6456@property (nonatomic , strong , readwrite ) id <UIViewProtocol> _interfaceView;
6557
@@ -258,140 +250,4 @@ - (void)sd_setImageWithURL:(nullable NSURL *)url
258250
259251@end
260252
261-
262- #define SDAnimatedImageInterfaceWrapperTag 123456789
263- #define SDAnimatedImageInterfaceWrapperSEL_layoutSubviews @" SDAnimatedImageInterfaceWrapper_layoutSubviews"
264- #define SDAnimatedImageInterfaceWrapperSEL_sizeThatFits @" SDAnimatedImageInterfaceWrapper_sizeThatFits:"
265-
266- // This using hook to implements the same logic like AnimatedImageViewWrapper.swift
267- static CGSize intrinsicContentSizeIMP (id <UIViewProtocol> self, SEL _cmd) {
268- struct objc_super superClass = {
269- self,
270- [self superclass ]
271- };
272- NSUInteger tag = self.tag ;
273- id <UIViewProtocol> interfaceView = self.subviews .firstObject ;
274- if (tag != SDAnimatedImageInterfaceWrapperTag || !interfaceView) {
275- return ((CGSize (*)(id , SEL ))objc_msgSendSuper)((__bridge id )(&superClass), _cmd);
276- }
277- CGSize size = interfaceView.intrinsicContentSize ;
278- if (size.width > 0 && size.height > 0 ) {
279- CGFloat aspectRatio = size.height / size.width ;
280- return CGSizeMake (1 , 1 * aspectRatio);
281- } else {
282- return CGSizeMake (-1 , -1 );
283- }
284- }
285-
286- static void layoutSubviewsIMP (id <UIViewProtocol> self, SEL _cmd) {
287- struct objc_super superClass = {
288- self,
289- [self superclass ]
290- };
291- NSUInteger tag = self.tag ;
292- id <UIViewProtocol> interfaceView = self.subviews .firstObject ;
293- if (tag != SDAnimatedImageInterfaceWrapperTag || !interfaceView) {
294- ((void (*)(id , SEL ))objc_msgSend)(self, NSSelectorFromString (SDAnimatedImageInterfaceWrapperSEL_layoutSubviews));
295- return ;
296- }
297- ((void (*)(id , SEL ))objc_msgSendSuper)((__bridge id )(&superClass), _cmd);
298- interfaceView.frame = self.bounds ;
299- }
300-
301- // This is suck that SwiftUI on watchOS will call extra sizeThatFits, we should always input size (already calculated with aspectRatio)
302- // iOS's wrapper don't need this
303- static CGSize sizeThatFitsIMP (id <UIViewProtocol> self, SEL _cmd, CGSize size) {
304- NSUInteger tag = self.tag ;
305- id <UIViewProtocol> interfaceView = self.subviews .firstObject ;
306- if (tag != SDAnimatedImageInterfaceWrapperTag || !interfaceView) {
307- return ((CGSize (*)(id , SEL ))objc_msgSend)(self, NSSelectorFromString (SDAnimatedImageInterfaceWrapperSEL_sizeThatFits));
308- }
309- return size;
310- }
311-
312- @implementation SDAnimatedImageInterfaceWrapper
313-
314- + (void )load {
315- static dispatch_once_t onceToken;
316- dispatch_once (&onceToken, ^{
317- Class class = NSClassFromString (@" SPInterfaceGroupView" );
318- // Implements `intrinsicContentSize`
319- SEL selector = @selector (intrinsicContentSize );
320- Method method = class_getInstanceMethod (class, selector);
321-
322- BOOL didAddMethod =
323- class_addMethod (class,
324- selector,
325- (IMP )intrinsicContentSizeIMP,
326- method_getTypeEncoding (method));
327- if (!didAddMethod) {
328- NSAssert (NO , @" SDAnimatedImageInterfaceWrapper will not work as expected." );
329- }
330-
331- // Override `layoutSubviews`
332- SEL originalSelector = @selector (layoutSubviews );
333- SEL swizzledSelector = NSSelectorFromString (SDAnimatedImageInterfaceWrapperSEL_layoutSubviews);
334- Method originalMethod = class_getInstanceMethod (class, originalSelector);
335-
336- didAddMethod =
337- class_addMethod (class,
338- swizzledSelector,
339- (IMP )layoutSubviewsIMP,
340- method_getTypeEncoding (originalMethod));
341- if (!didAddMethod) {
342- NSAssert (NO , @" SDAnimatedImageInterfaceWrapper will not work as expected." );
343- } else {
344- Method swizzledMethod = class_getInstanceMethod (class, swizzledSelector);
345- method_exchangeImplementations (originalMethod, swizzledMethod);
346- }
347-
348- // Override `sizeThatFits:`
349- originalSelector = @selector (sizeThatFits: );
350- swizzledSelector = NSSelectorFromString (SDAnimatedImageInterfaceWrapperSEL_sizeThatFits);
351- originalMethod = class_getInstanceMethod (class, originalSelector);
352-
353- didAddMethod =
354- class_addMethod (class,
355- swizzledSelector,
356- (IMP )sizeThatFitsIMP,
357- method_getTypeEncoding (originalMethod));
358- if (!didAddMethod) {
359- NSAssert (NO , @" SDAnimatedImageInterfaceWrapper will not work as expected." );
360- } else {
361- Method swizzledMethod = class_getInstanceMethod (class, swizzledSelector);
362- method_exchangeImplementations (originalMethod, swizzledMethod);
363- }
364- });
365- }
366-
367- - (instancetype )init {
368- Class cls = [self class ];
369- NSString *UUID = [NSUUID UUID ].UUIDString ;
370- NSString *property = [NSString stringWithFormat: @" %@ _%@ " , cls, UUID];
371- self = [self _initForDynamicCreationWithInterfaceProperty: property];
372- if (self) {
373- self.wrapped = [[SDAnimatedImageInterface alloc ] init ];
374- }
375- return self;
376- }
377-
378- - (NSDictionary *)interfaceDescriptionForDynamicCreation {
379- // This is called by WatchKit to provide default value
380- return @{
381- @" type" : @" group" ,
382- @" property" : self.interfaceProperty ,
383- @" radius" : @(0 ),
384- @" items" : @[self .wrapped.interfaceDescriptionForDynamicCreation], // This will create the native view and added to subview
385- };
386- }
387-
388- - (void )set_interfaceView : (id <UIViewProtocol>)interfaceView {
389- // This is called by WatchKit when native view created
390- [super set_interfaceView: interfaceView];
391- // Bind the interface object and native view
392- interfaceView.tag = SDAnimatedImageInterfaceWrapperTag;
393- self.wrapped ._interfaceView = interfaceView.subviews .firstObject ;
394- }
395-
396- @end
397253#endif
0 commit comments