gpt4 book ai didi

ios - 从当前 CAAnimation 的状态开始新的 CAAnimation

转载 作者:可可西里 更新时间:2023-11-01 04:22:44 29 4
gpt4 key购买 nike

我正在使用一对 CALayer 作为图像 mask ,让我能够以设定的速度制作灯泡填充或排空的动画,同时还可以跟随当前的触摸位置。也就是说,一个 mask 会随着触摸而跳动,而另一个会滑动到该位置。由于我使用了显式动画,因此在添加动画时我不得不设置 mask 滑动 mask 的位置。这意味着,如果我开始填充,然后在填充完成之前开始清空,空将从完成的填充位置开始(反之亦然)。

有没有办法获取动画的位置,设置动画每一步的位置,或者让新动画从事件动画的当前状态开始?

处理动画的代码如下:

- (void)masksFillTo:(CGFloat)height {
// Clamp the height we fill to inside the bulb. Remember Y gets bigger going down.
height = MIN(MAX(BULB_TOP, height), BULB_BOTTOM);

// We can find the target Y location by subtracting the Y value for the top of the
// bulb from the height.
CGFloat targetY = height - BULB_TOP;

// Find the bottom of the transparent mask to determine where the solid fill
// is sitting. Then find how far that fill needs to move.
// TODO: This works with the new set position, so overriding old anime doesn't work
CGFloat bottom = transMask.frame.origin.y + transMask.frame.size.height;

// If the target is above the bottom of the solid, we want to fill up.
// This means the empty mask jumps and the transparent mask slides.
CALayer *jumper;
CALayer *slider;
if (bottom - targetY >= 0) {
jumper = emptyMask;
slider = transMask;

// We need to reset the bottom to the emptyMask
bottom = emptyMask.frame.origin.y + emptyMask.frame.size.height;
} else {
jumper = transMask;
slider = emptyMask;
}

[jumper removeAllAnimations];
[slider removeAllAnimations];

CGFloat dy = bottom - targetY;

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
[jumper setPosition:CGPointMake(jumper.position.x, jumper.position.y - dy)];
[self slideMaskFillTo:height withMask:slider]; // Do this inside here or an odd flash glitch appears.
[CATransaction commit];
}

// TODO: Always starts from new position, even if animation hasn't reached it.
- (void)slideMaskFillTo:(CGFloat)height withMask:(CALayer *)slider {
// We can find the target Y location by subtracting the Y value for the top of the
// bulb from the height.
CGFloat targetY = height - BULB_TOP;

// We then find the bottom of the mask.
CGFloat bottom = slider.frame.origin.y + slider.frame.size.height;

CGFloat dy = bottom - targetY;

// Do the animation. Animating with duration doesn't appear to work properly.
// Apparently "When modifying layer properties from threads that don’t have a runloop,
// you must use explicit transactions."
CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"position"];
a.duration = (dy > 0 ? dy : -dy) / PXL_PER_SEC; // Should be 2 seconds for a full fill
a.fromValue = [NSValue valueWithCGPoint:slider.position];
CGPoint newPosition = slider.position;
newPosition.y -= dy;
a.toValue = [NSValue valueWithCGPoint:newPosition];
a.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[slider addAnimation:a forKey:@"colorize"];

// Update the actual position
slider.position = newPosition;
}

还有一个如何调用的例子。请注意,这意味着它可以称为中间动画。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self.view];

[self masksFillTo:point.y];
}

如果有人觉得它相关,那就是图像和蒙版的创建。

// Instantiate the different bulb images - empty, transparent yellow, and solid yellow. This
// includes setting the frame sizes. This approach found at http://stackoverflow.com/a/11218097/264775
emptyBulb = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Light.png"]];
transBulb = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Light-moving.png"]];
solidBulb = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Light-on.png"]];

[emptyBulb setFrame:CGRectMake(10, BULB_TOP, 300, BULB_HEIGHT)]; // 298 x 280
[transBulb setFrame:CGRectMake(10, BULB_TOP, 300, BULB_HEIGHT)]; // 298 x 280
[solidBulb setFrame:CGRectMake(10, BULB_TOP, 300, BULB_HEIGHT)]; // 298 x 280

[self.view addSubview:solidBulb]; // Empty on top, then trans, then solid.
[self.view addSubview:transBulb];
[self.view addSubview:emptyBulb];

// Create a mask for the empty layer so it will cover the other layers.
emptyMask = [CALayer layer];
[emptyMask setContentsScale:emptyBulb.layer.contentsScale]; // handle retina scaling
[emptyMask setFrame:emptyBulb.layer.bounds];
[emptyMask setBackgroundColor:[UIColor blackColor].CGColor];
emptyBulb.layer.mask = emptyMask;

// Also create a mask for the transparent image.
transMask = [CALayer layer];
[transMask setContentsScale:transBulb.layer.contentsScale]; // handle retina scaling
[transMask setFrame:transBulb.layer.bounds];
[transMask setBackgroundColor:[UIColor blackColor].CGColor];
transBulb.layer.mask = transMask;

最佳答案

刚刚通过 this answer 找到了解决方案.如果查看文档的正确部分,您会发现以下内容:

- (id)presentationLayer

Returns a copy of the layer containing all properties as they were at the start of the current transaction, with any active animations applied.

因此,如果我在首先检查透明蒙版位置(也称为实体层)之前添加此代码,我将获取当前动画位置并可以在填充和向下填充之间切换。

CALayer *temp;

if (transMask.animationKeys.count > 0) {
temp = transMask.presentationLayer;
transMask.position = temp.position;
}

if (emptyMask.animationKeys.count > 0) {
temp = emptyMask.presentationLayer;
emptyMask.position = temp.position;
}

关于ios - 从当前 CAAnimation 的状态开始新的 CAAnimation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11649837/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com