Tworzę reflektor, który porusza się nad treścią w mojej aplikacji, tak jak poniżej:Tworzenie animatable półprzezroczystą nakładkę z rdzeniem warstw animacji
W aplikacji próbki (pokazany powyżej), w tle warstwa jest niebieska i mam nad nią warstwę, która przyciemnia wszystko, oprócz okręgu, który pokazuje ją normalnie. Mam to działa (możesz zobaczyć, jak w poniższym kodzie). W mojej prawdziwej aplikacji jest obecna treść innych CALayerów, a nie tylko niebieski.
Oto mój problem: nie animuje. Używam rysunku CGContext
, aby utworzyć okrąg (który jest pustym miejscem w warstwie w przeciwnym wypadku). Po kliknięciu przycisku w mojej przykładowej aplikacji rysuję okrąg w innym rozmiarze w innym miejscu.
Chciałbym to płynnie przetłumaczyć i przeskalować, zamiast skakać, tak jak obecnie. Może wymagać innej metody tworzenia efektu reflektora lub może być sposób, w jaki nie wiem, aby domyślnie animować wywołanie -drawLayer:inContext:
.
Łatwo jest stworzyć aplikację próbki:
- utworzyć nową aplikację kakao (za pomocą ARC)
- Dodaj ramy Quartz
- upuść widok niestandardowy i przycisk na XIB
- Połącz niestandardowy widok z nową klasą (SpotlightView), z kodem podanym poniżej:
- Usuń
SpotlightView.h
, ponieważ zawarłem jego zawartość w SpotlightView.m - Ustaw wylot przycisk do działania
-moveSpotlight:
Update (własność mask
)
Lubię propozycja Davida Rönnqvist w komentarzach do korzystania z własności ciemnej warstwy mask
wyciąć otwór, który Mógłbym wtedy poruszać się samodzielnie. Problem polega na tym, że z jakiegoś powodu właściwość mask
działa odwrotnie, niż oczekuję od maski. Gdy podaję okrągłą maskę, wszystko, co się pojawi, to okrąg. Spodziewałem się, że maska zadziała w odwrotny sposób, zamaskowując obszar za pomocą 0
alfa.
Maskowanie to właściwa metoda, ale jeśli muszę wypełnić całą warstwę i wyciąć otwór, to mogę zrobić to tak, jak pierwotnie napisałem. Czy ktokolwiek wie, jak odwrócić właściwość -[CALayer mask]
, aby wycięty obszar został wycięty z obrazu warstwy?
/Aktualizacja
Oto kod dla 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
Czy próbowałeś ustawienie skali i tłumaczyć przekształcić na ciemną warstwę reflektor? –
@ DavidRönnqvist To nie zadziała, ponieważ warstwa z reflektorem jest wielkości całej "superlayer" – Dov
Czy reflektor może być maską do ciemnej warstwy? Możesz narysować reflektor w swojej własnej warstwie i ustawić jako maskę: właściwość na ciemnej warstwie. W ten sposób mógłbym animować rozmiar i pozycję reflektora, niezależnie od wielkości i położenia ciemnej warstwy. Jeszcze ich nie wypróbowałem. –