5

我正在尝试为自定义 UIView 的边界设置动画,同时保持其图层与其父视图的大小相同。为此,我试图在其父视图旁边为图层边界设置动画。我需要图层调用 drawLayer:withContext 作为其动画,因此我的自定义绘图将与边界一起正确更改大小。

在我开始动画之前,drawLayer 被正确调用并正确绘制。但是我无法让图层在边界动画的每个步骤上调用其 drawLayer 方法。相反,它只调用一次,立即跳转到动画最后一帧的“结束边界”。

// 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];

为什么边界不报告其动画的变化(不仅仅是最后一帧)?我究竟做错了什么?

4

3 回答 3

3

这可能会或可能不会有帮助......

许多人不知道 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.aeth.com/iOSBook/ch17.html#_making_a_property_animatable

于 2013-04-14T18:36:52.167 回答
1

首先,层支持(或托管)视图的层总是调整大小以适应其父视图的边界。如果您将视图设置为图层委托,则视图将在每一帧接收到 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
于 2013-04-14T18:25:25.473 回答
1

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

当您为图层属性设置动画时,它将立即在模型层中设置为其最终值(如您所见),并且实际动画在表示层中完成。

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

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

由于您没有提供您的drawLayer:withContext方法,因此不清楚您想在动画期间绘制什么,但如果您想为自定义属性设置动画,这里有一个很好的教程

于 2013-04-14T17:06:02.317 回答