Files
yoga/YogaKit/Source/UIView+Yoga.m

151 lines
4.1 KiB
Mathematica
Raw Normal View History

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <objc/runtime.h>
#import "UIView+Yoga.h"
#import "YGLayout+Private.h"
static const void* kYGYogaAssociatedKey = &kYGYogaAssociatedKey;
@implementation UIView (YogaKit)
- (YGLayout*)yoga {
YGLayout* yoga = objc_getAssociatedObject(self, kYGYogaAssociatedKey);
if (!yoga) {
yoga = [[YGLayout alloc] initWithView:self];
objc_setAssociatedObject(
self, kYGYogaAssociatedKey, yoga, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return yoga;
}
- (BOOL)isYogaEnabled {
return objc_getAssociatedObject(self, kYGYogaAssociatedKey) != nil;
}
- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block {
if (block != nil) {
block(self.yoga);
}
}
@end
static const void* kYGBoundsSizeAssociatedKey = &kYGBoundsSizeAssociatedKey;
static void YogaSwizzleInstanceMethod(Class cls, SEL originalSelector, SEL swizzledSelector);
@implementation UIView (YogaKitAutoApplyLayout)
+ (void)load {
2020-08-13 21:44:57 +08:00
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
YogaSwizzleInstanceMethod(self, @selector(initWithFrame:), @selector(_yoga_initWithFrame:));
YogaSwizzleInstanceMethod(self, @selector(setFrame:), @selector(_yoga_setFrame:));
YogaSwizzleInstanceMethod(self, @selector(setBounds:), @selector(_yoga_setBounds:));
#if TARGET_OS_OSX
YogaSwizzleInstanceMethod(self, @selector(setFrameSize:), @selector(_yoga_setFrameSize:));
YogaSwizzleInstanceMethod(self, @selector(setBoundsSize:), @selector(_yoga_setBoundsSize:));
#endif
});
}
- (CGSize)_yoga_boundsSize {
2020-08-13 21:44:57 +08:00
NSValue *value = (NSValue *)objc_getAssociatedObject(self, kYGBoundsSizeAssociatedKey);
return value ?
#if TARGET_OS_OSX
value.sizeValue
#else
value.CGSizeValue
#endif
: CGSizeMake(YGUndefined, YGUndefined);
}
- (void)set_yoga_boundsSize:(CGSize)size {
2020-08-13 21:44:57 +08:00
objc_setAssociatedObject(self,
kYGBoundsSizeAssociatedKey,
#if TARGET_OS_OSX
[NSValue valueWithSize:size]
#else
[NSValue valueWithCGSize:size]
#endif
, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (instancetype)_yoga_initWithFrame:(CGRect)frame {
2020-08-13 21:44:57 +08:00
id _self = [self _yoga_initWithFrame:frame];
if (_self) {
[self _yoga_applyLayout];
}
2020-08-13 21:44:57 +08:00
return _self;
}
- (void)_yoga_setFrame:(CGRect)frame {
2020-08-13 21:44:57 +08:00
[self _yoga_setFrame:frame];
2020-08-13 21:44:57 +08:00
[self _yoga_applyLayout];
}
- (void)_yoga_setBounds:(CGRect)bounds {
2020-08-13 21:44:57 +08:00
[self _yoga_setBounds:bounds];
2020-08-13 21:44:57 +08:00
[self _yoga_applyLayout];
}
#if TARGET_OS_OSX
- (void)_yoga_setFrameSize:(NSSize)newSize {
[self _yoga_setFrameSize:newSize];
[self _yoga_applyLayout];
}
- (void)_yoga_setBoundsSize:(NSSize)newSize {
[self _yoga_setBoundsSize:newSize];
[self _yoga_applyLayout];
}
2020-08-13 21:44:57 +08:00
#endif
- (void)_yoga_applyLayout {
if (self.isYogaEnabled && self.yoga.isEnabled) {
CGSize size = self.bounds.size;
CGSize prev = self._yoga_boundsSize;
if (!CGSizeEqualToSize(size, prev)) {
self._yoga_boundsSize = size;
[self.yoga applyLayoutPreservingOrigin:YES];
}
}
}
@end
static void YogaSwizzleInstanceMethod(Class cls, SEL originalSelector, SEL swizzledSelector) {
if (!cls || !originalSelector || !swizzledSelector) {
return;
}
Method originalMethod = class_getInstanceMethod(cls, originalSelector);
Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
if (!originalMethod || !swizzledMethod) {
return;
}
IMP swizzledIMP = method_getImplementation(swizzledMethod);
if (class_addMethod(cls, originalSelector, swizzledIMP, method_getTypeEncoding(swizzledMethod))) {
class_replaceMethod(cls,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}