无法让 CALayer 更新其绘制图层:在边界动画期间



我试图动画自定义UIView的边界,同时也保持其层的大小与其父视图相同。为了做到这一点,我试着让图层的边界在它的父视图旁边动起来。我需要图层调用drawLayer:withContext作为它的动画,所以我的自定义绘图将随着边界正确地改变大小。

drawLayer被正确调用,并在我开始动画之前正确绘制。但是我不能让图层在边界动画的每一步都调用它的drawLayer方法。相反,它只调用ONCE,立即跳到动画最后一帧的"结束边界"。

// self.bg is a property pointing to my custom UIView
self.bg.layer.needsDisplayOnBoundsChange = YES;
self.bg.layer.mask.needsDisplayOnBoundsChange = YES;
[UIView animateWithDuration:2 delay:0 options:UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionAutoreverse|UIViewAnimationOptionRepeat animations:^{
    [CATransaction begin];
    self.bg.layer.bounds = bounds;
    self.bg.layer.mask.bounds = bounds;
    [CATransaction commit];
    self.bg.bounds = bounds;
} completion:nil];

为什么边界不报告一个变化作为它的动画(不只是最后一帧)?我做错了什么?

这可能有帮助,也可能没有帮助…

很多人都不知道Core Animation有一个非常酷的功能,允许你定义自己的图层属性,这样它们就可以被动画化。我使用的一个例子是给CALayer子类一个thickness属性。当我用Core Animation制作动画时…

CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"thickness"];
ba.toValue = @10.0f;
ba.autoreverses = YES;
[lay addAnimation:ba forKey:nil];

…效果是在整个动画中反复调用drawInContext:drawLayer:...,允许我在每个时刻根据其当前 thickness属性值(动画过程中的中间值)反复更改图层的绘制方式。

在我看来,可能是你所追求的东西。如果是这样,您可以在这里找到一个可下载的示例:

https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/ch17p498customAnimatableProperty

讨论(从我的书)在这里:

http://www.apeth.com/iOSBook/ch17.html _making_a_property_animatable

这是因为您要绘制的图层与屏幕上显示的图层不同。

当你动画一个图层属性时,它会立即被设置为模型层的最终值,(正如你已经注意到的),而实际的动画是在表示层完成的。

您可以访问表示层并查看动画属性的实际值:

CALayer *presentationLayer = (CALayer *)[self.bg.layer presentationLayer];
...

因为你没有提供你的drawLayer:withContext方法,这是不清楚你想在动画期间画什么,但如果你想动画自定义属性,这里是一个很好的教程。

首先,图层支持(或托管)视图的图层总是调整大小以适应其父视图的边界。如果你将视图设置为图层委托,那么视图将在每一帧接收drawLayer:inContext:。当然,你必须确保如果你的图层有needsDisplayOnBoundsChange == YES .

这是一个例子(在Mac上)调整窗口的大小,然后改变底层的路径。

// My Nib contains one view and one button. 
// The view has a MPView class and the button action is resizeWindow:
@interface MPView() {
    CAShapeLayer     *_hostLayer;
    CALayer          *_outerLayer;
    CAShapeLayer     *_innerLayer;
}
@end
@implementation MPView
- (void)awakeFromNib
{
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    _hostLayer = [CAShapeLayer layer];
    _hostLayer.backgroundColor = [NSColor blackColor].CGColor;
    _hostLayer.borderColor = [NSColor redColor].CGColor;
    _hostLayer.borderWidth = 2;
    _hostLayer.needsDisplayOnBoundsChange = YES;
    _hostLayer.delegate = self;
    _hostLayer.lineWidth = 4;
    _hostLayer.strokeColor = [NSColor greenColor].CGColor;
    _hostLayer.needsDisplayOnBoundsChange = YES;
    self.layer = _hostLayer;
    self.wantsLayer = YES;
    [CATransaction commit];
    [self.window setFrame:CGRectMake(100, 100, 200, 200) display:YES animate:NO];
}
- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
    if (layer == _hostLayer) {
        CGSize size = layer.bounds.size;
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, 0, 0);
        CGPathAddLineToPoint(path, NULL, size.width, size.height);
        _hostLayer.path = path;
        CGPathRelease(path);
    }
}
- (IBAction)resizeWindow:(id)sender
{
    [self.window setFrame:CGRectMake(100, 100, 1200, 800) display:YES animate:YES];
}
@end

最新更新