A terrible, terrible hack to toggle AppKit's destruction of layer modifications.
#import <Cocoa/Cocoa.h> | |
@interface LBHView : NSView | |
/// This property controls whether the view can indirectly control its | |
/// backing layer's properties, specifically the following: | |
/// `affineTransform` | |
/// `anchorPoint` | |
/// | |
/// These properties cannot be modified on the layer during the time that | |
/// this property is enabled. | |
/// | |
/// This is useful for preventing NSView from resetting custom modifications | |
/// to the layer, such as transforms for custom animations. | |
@property (nonatomic, assign) BOOL ignoreNSViewBackingLayerSynchronization; | |
@end |
#import "LBHView.h" | |
#import "JRSwizzle.h" | |
#import <objc/runtime.h> | |
@interface CALayer (LBHBackingLayerHacks) | |
@property (nonatomic, assign) BOOL lbh_ignoreNSViewBackingLayerSynchronization; | |
@end | |
static void *LBHBackingLayerSynchronizationAssociatedObjectKey = &LBHBackingLayerSynchronizationAssociatedObjectKey; | |
@implementation CALayer (LBHBackingLayerHacks) | |
- (void)setLbh_ignoreNSViewBackingLayerSynchronization:(BOOL)ignores { | |
objc_setAssociatedObject(self, LBHBackingLayerSynchronizationAssociatedObjectKey, @(ignores), OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
} | |
- (BOOL)lbh_ignoreNSViewBackingLayerSynchronization { | |
return [objc_getAssociatedObject(self, LBHBackingLayerSynchronizationAssociatedObjectKey) boolValue]; | |
} | |
- (void)lbh_setAffineTransform:(CGAffineTransform)m { | |
if (self.lbh_ignoreNSViewBackingLayerSynchronization) { | |
// do nothing | |
} else { | |
[self lbh_setAffineTransform:m]; | |
} | |
} | |
- (void)lbh_setAnchorPoint:(CGPoint)anchorPoint { | |
if (self.lbh_ignoreNSViewBackingLayerSynchronization) { | |
// do nothing | |
} else { | |
[self lbh_setAnchorPoint:anchorPoint]; | |
} | |
} | |
@end | |
@implementation LBHView | |
- (instancetype)initWithFrame:(NSRect)frameRect { | |
self = [super initWithFrame:frameRect]; | |
if (self == nil) return nil; | |
self.wantsLayer = YES; | |
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay; | |
return self; | |
} | |
- (CALayer *)makeBackingLayer { | |
CALayer *backingLayer = [super makeBackingLayer]; | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
// Get the class for _NSBackingLayer. | |
Class nsBackingLayerClass = backingLayer.class; | |
NSError *error = nil; | |
// Swizzle the setters for anchor point and affine transform. | |
[nsBackingLayerClass jr_swizzleMethod:@selector(setAnchorPoint:) withMethod:@selector(lbh_setAnchorPoint:) error:&error]; | |
[nsBackingLayerClass jr_swizzleMethod:@selector(setAffineTransform:) withMethod:@selector(lbh_setAffineTransform:) error:&error]; | |
if (error != nil) { | |
NSLog(@"Fatal error: could not swizzle the view's backing layer! %@", error); | |
} | |
}); | |
return backingLayer; | |
} | |
- (void)setIgnoreNSViewBackingLayerSynchronization:(BOOL)ignoreSynchronization { | |
self.layer.lbh_ignoreNSViewBackingLayerSynchronization = ignoreSynchronization; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment