简体   繁体   中英

NSView CALayer Opacity Madness

It seems as though the layer's properties of my NSView are sometimes not editable/wrong. In the code below, the animation works perfectly, and all appears normal. The output from the NSlogs are always :

anim over opacity = 1.00000
first opacity = 0.50000
current opacity = 0.00000
updated opacity = 0.00000

The first two logs look right, so even at animation did stop, the layer seems to operate normally. However, some time later, when I check the opacity it magically turned to 0. Further wrong, when I set the layer's opacity to 1, and check it immediately after, it still is 0. How is that possible?

I goofed around with setneedsdisplay in the layer and setneedsdisplay:YES in nsview and that didn't help. Any suggestions are greatly appreciated.

- (void) someSetupAnimationMethod {
        aLayer = [CALayer layer];
        [theView setWantsLayer:YES];
        [theView setLayer:aLayer];

        [aLayer setOpacity:0.0];
        CABasicAnimation *opacity = [CABasicAnimation animationWithKeyPath:@"opacity"];
        opacity.byValue = [NSNumber numberWithFloat:1.0];
        opacity.duration = 0.3;
        opacity.delegate = self;
        opacity.fillMode = kCAFillModeForwards;
        opacity.removedOnCompletion = NO;
        [opacity setValue:@"opacity done" forKey:@"animation"];
        [aLayer addAnimation:opacity forKey:nil];
    }

    - (void) animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
        if([[anim valueForKey:@"animation"] isEqualToString:@"opacity done"]) {
           NSLog(@"anim over opacity = %f", aLayer.opacity);
           aLayer.opacity = 0.5;
           [aLyaer removeAllAnimations];
           NSLog(@"first opacity = %f", aLayer.opacity);
        }
    }

    - (void) someLaterMethod {
        NSLog(@"current opacity = %f", aLayer.opacity);
        aLayer.opacity = 1.0;
        NSLog(@"updated opacity = %f", aLayer.opacity);
    }

You're breaking a fundamental CALayer / NSView rule by creating a layer-backed view and then trying to manipulate the layer directly.

aLayer = [CALayer layer];
[theView setWantsLayer:YES];
[theView setLayer:aLayer];

When you tell the view to use a layer before calling setLayer: , the view becomes "layer-backed" -- it is simply using the layer as a buffer and all drawing that you want to do should be done through the usual drawRect: and related methods. You are not allowed to touch the layer directly. If you change the order of those calls:

[theView setLayer:aLayer];
[theView setWantsLayer:YES];

You now have a "layer-hosting" view, which means that the view just provides a space on the screen for the layer to be drawn into. In this case, you do your drawing directly into the layer. Since the contents of the layer become the contents of the view, you cannot add subviews or use the view's drawing mechanisms.

This is mentioned in the -[NSView setWantsLayer:] documentation; I also found an old cocoa-dev thread that explains it pretty well.

I'm not certain that this will fix your problem, but as far as I can see you're doing everything else correctly, such as setting the fill mode and updating the value after the animation finishes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM