Dov*_*Dov 6 macos cocoa drawing core-animation calayer
我正在创建一个聚焦在我的应用程序中移动内容的聚光灯,如下所示:

在示例应用程序(如上所示)中,背景图层是蓝色的,我在其上面有一个图层使所有图层变暗,除了正常显示它的圆圈.我有这个工作(你可以在下面的代码中看到).在我的真实应用中,其他CALayers中有实际内容,而不仅仅是蓝色.
这是我的问题:它没有动画.我正在使用CGContext绘图来创建圆圈(这是一个黑色图层中的空白点).当您单击我的示例应用程序中的按钮时,我会在不同位置绘制不同大小的圆圈.
我希望能够顺利地翻译和扩展,而不是像目前那样跳跃.它可能需要一种不同的方法来创建聚光灯效果,或者可能有一种我不知道的方式隐式地为-drawLayer:inContext:调用设置动画.
创建示例应用程序很容易:
SpotlightView.h,因为我将其内容包含在SpotlightView.m中-moveSpotlight:操作更新(mask属性)
我喜欢DavidRönnqvist在评论中建议使用mask黑暗层的属性来切出一个洞,然后我可以独立移动.问题在于,由于某种原因,该mask属性与我期望掩码工作的方式相反.当我指定一个圆形蒙版时,所有显示的都是圆形.我期望掩码以相反的方式工作,用0alpha 屏蔽区域.
掩盖感觉是正确的方法,但如果我必须填写整个图层并切出一个洞,那么我也可以按照我最初发布的方式进行操作.有谁知道如何反转-[CALayer mask]属性,以便绘制的区域从图层的图像中被切除?
/更新
这是以下代码SpotlightView:
//
// SpotlightView.m
//
#import <Quartz/Quartz.h>
@interface SpotlightView : NSView
- (IBAction)moveSpotlight:(id)sender;
@end
@interface SpotlightView ()
@property (strong) CALayer *spotlightLayer;
@property (assign) CGRect highlightRect;
@end
@implementation SpotlightView
@synthesize spotlightLayer;
@synthesize highlightRect;
- (id)initWithFrame:(NSRect)frame {
if ((self = [super initWithFrame:frame])) {
self.wantsLayer = YES;
self.highlightRect = CGRectNull;
self.spotlightLayer = [CALayer layer];
self.spotlightLayer.frame = CGRectInset(self.layer.bounds, -50, -50);
self.spotlightLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
self.spotlightLayer.opacity = 0.60;
self.spotlightLayer.delegate = self;
CIFilter *blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
[blurFilter setValue:[NSNumber numberWithFloat:5.0]
forKey:@"inputRadius"];
self.spotlightLayer.filters = [NSArray arrayWithObject:blurFilter];
[self.layer addSublayer:self.spotlightLayer];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {}
- (void)moveSpotlight:(id)sender {
[self.spotlightLayer setNeedsDisplay];
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
if (layer == self.spotlightLayer) {
CGContextSaveGState(ctx);
CGColorRef blackColor = CGColorCreateGenericGray(0.0, 1.0);
CGContextSetFillColorWithColor(ctx, blackColor);
CGColorRelease(blackColor);
CGContextClearRect(ctx, layer.bounds);
CGContextFillRect(ctx, layer.bounds);
// Causes the toggling
if (CGRectIsNull(self.highlightRect) || self.highlightRect.origin.x != 25) {
self.highlightRect = CGRectMake(25, 25, 100, 100);
} else {
self.highlightRect = CGRectMake(NSMaxX(self.layer.bounds) - 50,
NSMaxY(self.layer.bounds) - 50,
25, 25);
}
CGRect drawnRect = [layer convertRect:self.highlightRect
fromLayer:self.layer];
CGMutablePathRef highlightPath = CGPathCreateMutable();
CGPathAddEllipseInRect(highlightPath, NULL, drawnRect);
CGContextAddPath(ctx, highlightPath);
CGContextSetBlendMode(ctx, kCGBlendModeClear);
CGContextFillPath(ctx);
CGPathRelease(highlightPath);
CGContextRestoreGState(ctx);
}
else {
CGColorRef blueColor = CGColorCreateGenericRGB(0, 0, 1.0, 1.0);
CGContextSetFillColorWithColor(ctx, blueColor);
CGContextFillRect(ctx, layer.bounds);
CGColorRelease(blueColor);
}
}
@end
Run Code Online (Sandbox Code Playgroud)
我终于明白了.是什么促使我回答的是听到CAShapeLayer全班同学的意见.起初,我认为绘制图层内容是一种更简单的方法,而不是绘制和清除标准的内容CALayer.但我阅读了该path属性的文档CAShapeLayer,其中说明它可能是动画的,但不是含蓄的.
虽然图层蒙版可能更直观和优雅,但似乎不可能使用蒙版来隐藏所有者图层的一部分,而不是显示部分,因此我无法使用它.我很满意这个解决方案,因为它很清楚发生了什么.我希望它使用隐式动画,但动画代码只有几行.
下面,我修改了问题中的示例代码以添加平滑动画.(我删除了CIFilter代码,因为它是无关紧要的.解决方案仍然适用于过滤器.)
//
// SpotlightView.m
//
#import <Quartz/Quartz.h>
@interface SpotlightView : NSView
- (IBAction)moveSpotlight:(id)sender;
@end
@interface SpotlightView ()
@property (strong) CAShapeLayer *spotlightLayer;
@property (assign) CGRect highlightRect;
@end
@implementation SpotlightView
@synthesize spotlightLayer;
@synthesize highlightRect;
- (id)initWithFrame:(NSRect)frame {
if ((self = [super initWithFrame:frame])) {
self.wantsLayer = YES;
self.highlightRect = CGRectNull;
self.spotlightLayer = [CAShapeLayer layer];
self.spotlightLayer.frame = self.layer.bounds;
self.spotlightLayer.autoresizingMask = kCALayerWidthSizable | kCALayerHeightSizable;
self.spotlightLayer.fillRule = kCAFillRuleEvenOdd;
CGColorRef blackoutColor = CGColorCreateGenericGray(0.0, 0.60);
self.spotlightLayer.fillColor = blackoutColor;
CGColorRelease(blackoutColor);
[self.layer addSublayer:self.spotlightLayer];
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect {}
- (CGPathRef)newSpotlightPathInRect:(CGRect)containerRect
withHighlight:(CGRect)spotlightRect {
CGMutablePathRef shape = CGPathCreateMutable();
CGPathAddRect(shape, NULL, containerRect);
if (!CGRectIsNull(spotlightRect)) {
CGPathAddEllipseInRect(shape, NULL, spotlightRect);
}
return shape;
}
- (void)moveSpotlight {
CGPathRef toShape = [self newSpotlightPathInRect:self.spotlightLayer.bounds
withHighlight:self.highlightRect];
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
pathAnimation.fromValue = (__bridge id)self.spotlightLayer.path;
pathAnimation.toValue = (__bridge id)toShape;
[self.spotlightLayer addAnimation:pathAnimation forKey:@"path"];
self.spotlightLayer.path = toShape;
CGPathRelease(toShape);
}
- (void)moveSpotlight:(id)sender {
if (CGRectIsNull(self.highlightRect) || self.highlightRect.origin.x != 25) {
self.highlightRect = CGRectMake(25, 25, 100, 100);
} else {
self.highlightRect = CGRectMake(NSMaxX(self.layer.bounds) - 50,
NSMaxY(self.layer.bounds) - 50,
25, 25);
}
[self moveSpotlight];
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
CGColorRef blueColor = CGColorCreateGenericRGB(0, 0, 1.0, 1.0);
CGContextSetFillColorWithColor(ctx, blueColor);
CGContextFillRect(ctx, layer.bounds);
CGColorRelease(blueColor);
}
@end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1374 次 |
| 最近记录: |