Sto creando un riflettore che si muove sul contenuto nella mia app, in questo modo:Creazione di un overlay trasparente animatable con strati Core Animation
Nell'applicazione del campione (vedi sopra), lo sfondo il livello è blu e su di esso ho uno strato che si scurisce tutto tranne un cerchio che lo mostra normalmente. Ho funzionato (puoi vedere come nel codice qui sotto). Nella mia vera app, ci sono contenuti reali in altri CALayer, piuttosto che blu.
Ecco il mio problema: non si anima. Sto usando il disegno CGContext
per creare il cerchio (che è un punto vuoto in un livello altrimenti nero). Quando fai clic sul pulsante nella mia app di esempio, disegno il cerchio con una dimensione diversa in una posizione diversa.
Mi piacerebbe che per tradurre e ridimensionare senza problemi, invece di saltare, come al momento. Potrebbe essere necessario un diverso metodo per creare l'effetto spotlight o potrebbe non esserci un modo per cui non conosco per animare implicitamente la chiamata -drawLayer:inContext:
.
E 'facile creare l'applicazione di esempio:
- fare un nuovo cacao app (usando ARC)
- Aggiungere il quadro Quartz
- goccia una visualizzazione personalizzata e un pulsante sul XIB
- Collega la visualizzazione personalizzata a una nuova classe (SpotlightView), con codice fornito sotto
- Elimina
SpotlightView.h
, poiché ho incluso il suo contenuto in SpotlightView.m - Impostare uscita del pulsante per l'azione
-moveSpotlight:
Update (la proprietà mask
)
Mi piace il suggerimento di David Rönnqvist nei commenti l'utilizzo della proprietà mask
dello strato oscurato per tagliare un buco, che Potrei quindi muovermi indipendentemente. Il problema è che per qualche motivo, la proprietà mask
funziona al contrario di come mi aspetto che una maschera funzioni. Quando specifico una maschera circolare, tutto ciò che appare è il cerchio. Mi aspettavo che la maschera funzionasse nel modo opposto, mascherando l'area con 0
alfa.
Il mascheramento sembra la soluzione giusta per questo, ma se devo riempire l'intero livello e ritagliare un buco, allora posso anche farlo nel modo in cui ho originariamente pubblicato. Qualcuno sa come invertire la proprietà -[CALayer mask]
, in modo che l'area disegnata venga ritagliata dall'immagine del livello?
/Aggiornamento
Ecco il codice per 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
Avete provato a fissare una scala e tradurre trasformare sullo strato riflettori buio? –
@ DavidRönnqvist Questo non funzionerà, perché il livello con il riflettore è la dimensione dell'intero 'superlayer' – Dov
Il riflettore potrebbe essere la maschera al livello scuro? È possibile disegnare il riflettore nel proprio livello e impostarlo come -mask: proprietà sul livello scuro. In questo modo penso che potresti animare la dimensione e la posizione del riflettore indipendentemente dalle dimensioni e dalla posizione del livello scuro. Non l'hai ancora provato. –