在 iOS 中使用 NSThread 重新触发 CABasicAnimation

发布于 2024-11-04 00:35:40 字数 3978 浏览 0 评论 0原文

我正在破解这个核心动画示例: https://github.com/joericioppo/Shape_05

我想重新触发动画以响应 NSThread。 NSLogs 按预期显示,但动画本身在所有睡眠完成之前不会触发,即使其方法已被验证调用。我怎样才能每秒重新触发这个动画?

顺便说一句 - 这只是我正在开发的一个示例补丁,以便理解这个概念。我知道动画可以设置为重复,但由于各种原因这不是我想要做的。这是代码,非常欢迎任何帮助,谢谢。

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface Shape_05ViewController : UIViewController {

    CALayer                     *rootLayer;

    CAShapeLayer            *shapeLayer;

    CGMutablePathRef        pentagonPath;
    CGMutablePathRef        starPath;

    int animationCount;
    CABasicAnimation *animation;

}

-(void)startAnimation;
-(void) viewDidLoad;
-(void) startSequence;
-(void) enactSequence;

@end

#import "Shape_05ViewController.h"

@implementation Shape_05ViewController


- (void)loadView 
{

    UIView *appView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    appView.backgroundColor = [UIColor blackColor];
    self.view = appView;
    [appView release];
    rootLayer   = [CALayer layer];
    rootLayer.frame = self.view.bounds;
    [self.view.layer addSublayer:rootLayer];


    //Pentagon Path

    pentagonPath = CGPathCreateMutable();
    CGPoint center = self.view.center;
    CGPathMoveToPoint(pentagonPath, nil, center.x, center.y - 75.0);

    for(int i = 1; i < 5; ++i) {
        CGFloat x = - 75.0 * sinf(i * 2.0 * M_PI / 5.0);
        CGFloat y =  - 75.0 * cosf(i * 2.0 * M_PI / 5.0);
        CGPathAddLineToPoint(pentagonPath, nil,center.x + x, center.y + y);
    }
    CGPathCloseSubpath(pentagonPath); //This seems to be fixed in 4.0

    //Star Path

    starPath = CGPathCreateMutable();
    center = self.view.center;
    CGPathMoveToPoint(starPath, NULL, center.x, center.y + 75.0);
    for(int i = 1; i < 5; ++i) {
        CGFloat x =  75.0 * sinf(i * 4.0 * M_PI / 5.0);
        CGFloat y =  75.0 * cosf(i * 4.0 * M_PI / 5.0);
        CGPathAddLineToPoint(starPath, NULL, center.x + x, center.y + y);
    };
    CGPathCloseSubpath(starPath);


    //Create Shape

    shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = pentagonPath;
    UIColor *fillColor = [UIColor colorWithWhite:0.9 alpha:1.0];
    shapeLayer.fillColor = fillColor.CGColor; 
    shapeLayer.fillRule = kCAFillRuleNonZero;
    [rootLayer addSublayer:shapeLayer];

}


-(void) viewDidLoad {

    NSLog(@"viewDidLoad");
    animationCount = 0;
    [NSThread detachNewThreadSelector:@selector(startSequence) toTarget:self withObject:nil];

}

-(void) startSequence {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [self enactSequence];
    //[NSThread sleepForTimeInterval:100];

    [pool release];

}
-(void) enactSequence {
    NSLog(@"enactSequence");
    for(int i = 0; i < 4; i++) {
        [NSThread sleepForTimeInterval:1];
        [self performSelector:@selector(startAnimation) withObject:nil];
        [rootLayer setNeedsDisplay];
        NSLog(@"%i", i);
    };

}


-(void)startAnimation
{   
    NSLog(@"startAnimation");

    animation = [CABasicAnimation animationWithKeyPath:@"path"];
    animation.duration = 0.25;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.repeatCount = 0;
    animation.autoreverses = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = YES;

    if( (animationCount % 2) == 0) {
        animation.fromValue = (id)pentagonPath;
        animation.toValue = (id)starPath;
    } else {
        animation.fromValue = (id)starPath;
        animation.toValue = (id)pentagonPath;
    };


    [shapeLayer addAnimation:animation forKey:@"animatePath"];

    animationCount++;

}


- (void)didReceiveMemoryWarning 
{
    [super didReceiveMemoryWarning];
}


- (void)dealloc
{
    CGPathRelease(starPath);
    CGPathRelease(pentagonPath);
    [super dealloc];
}


@end

I am hacking this Core Animation example:
https://github.com/joericioppo/Shape_05

I want to retrigger the animation in response to an NSThread. The NSLogs show up as expected, but the animation itself does not trigger until all sleeps have completed, even though its method has verifiably been called. How can I retrigger this animation every second?

By the way - this is just an example patch I am working on in order to understand the concept. I know that animations can be set to repeat, but this isn't what I want to do, for various reasons. Here's the code, any help would be most welcome, thanks.

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

@interface Shape_05ViewController : UIViewController {

    CALayer                     *rootLayer;

    CAShapeLayer            *shapeLayer;

    CGMutablePathRef        pentagonPath;
    CGMutablePathRef        starPath;

    int animationCount;
    CABasicAnimation *animation;

}

-(void)startAnimation;
-(void) viewDidLoad;
-(void) startSequence;
-(void) enactSequence;

@end

#import "Shape_05ViewController.h"

@implementation Shape_05ViewController


- (void)loadView 
{

    UIView *appView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    appView.backgroundColor = [UIColor blackColor];
    self.view = appView;
    [appView release];
    rootLayer   = [CALayer layer];
    rootLayer.frame = self.view.bounds;
    [self.view.layer addSublayer:rootLayer];


    //Pentagon Path

    pentagonPath = CGPathCreateMutable();
    CGPoint center = self.view.center;
    CGPathMoveToPoint(pentagonPath, nil, center.x, center.y - 75.0);

    for(int i = 1; i < 5; ++i) {
        CGFloat x = - 75.0 * sinf(i * 2.0 * M_PI / 5.0);
        CGFloat y =  - 75.0 * cosf(i * 2.0 * M_PI / 5.0);
        CGPathAddLineToPoint(pentagonPath, nil,center.x + x, center.y + y);
    }
    CGPathCloseSubpath(pentagonPath); //This seems to be fixed in 4.0

    //Star Path

    starPath = CGPathCreateMutable();
    center = self.view.center;
    CGPathMoveToPoint(starPath, NULL, center.x, center.y + 75.0);
    for(int i = 1; i < 5; ++i) {
        CGFloat x =  75.0 * sinf(i * 4.0 * M_PI / 5.0);
        CGFloat y =  75.0 * cosf(i * 4.0 * M_PI / 5.0);
        CGPathAddLineToPoint(starPath, NULL, center.x + x, center.y + y);
    };
    CGPathCloseSubpath(starPath);


    //Create Shape

    shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = pentagonPath;
    UIColor *fillColor = [UIColor colorWithWhite:0.9 alpha:1.0];
    shapeLayer.fillColor = fillColor.CGColor; 
    shapeLayer.fillRule = kCAFillRuleNonZero;
    [rootLayer addSublayer:shapeLayer];

}


-(void) viewDidLoad {

    NSLog(@"viewDidLoad");
    animationCount = 0;
    [NSThread detachNewThreadSelector:@selector(startSequence) toTarget:self withObject:nil];

}

-(void) startSequence {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    [self enactSequence];
    //[NSThread sleepForTimeInterval:100];

    [pool release];

}
-(void) enactSequence {
    NSLog(@"enactSequence");
    for(int i = 0; i < 4; i++) {
        [NSThread sleepForTimeInterval:1];
        [self performSelector:@selector(startAnimation) withObject:nil];
        [rootLayer setNeedsDisplay];
        NSLog(@"%i", i);
    };

}


-(void)startAnimation
{   
    NSLog(@"startAnimation");

    animation = [CABasicAnimation animationWithKeyPath:@"path"];
    animation.duration = 0.25;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    animation.repeatCount = 0;
    animation.autoreverses = NO;
    animation.fillMode = kCAFillModeForwards;
    animation.removedOnCompletion = YES;

    if( (animationCount % 2) == 0) {
        animation.fromValue = (id)pentagonPath;
        animation.toValue = (id)starPath;
    } else {
        animation.fromValue = (id)starPath;
        animation.toValue = (id)pentagonPath;
    };


    [shapeLayer addAnimation:animation forKey:@"animatePath"];

    animationCount++;

}


- (void)didReceiveMemoryWarning 
{
    [super didReceiveMemoryWarning];
}


- (void)dealloc
{
    CGPathRelease(starPath);
    CGPathRelease(pentagonPath);
    [super dealloc];
}


@end

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

浮生未歇 2024-11-11 00:35:40

再次谷歌搜索后确定:
http://forums.macrumors.com/showthread.php?t= 749518&highlight=cabasicanimation

我发现了这个叫做 NSTimer 的东西!对该网站的另一次搜索发现了一些好信息:
如何使用 NSTimer?

关于在自己的线程中运行 NSTimer:
无限期地保留包含 NSTimer 的 NSThread 吗? (iPhone)

所以现在我可以提供这个更新的代码示例,我希望有一天它可能对某人有用。顺便说一句,我还没有尝试过,但显然可以使用以下方法来停止计时器:

[myTimer invalidate];
myTimer = nil;

感谢本网站的所有人,不仅是网络上设计最精美的角落,而且还是一个完全的救星!

    #import <UIKit/UIKit.h>
    #import <QuartzCore/QuartzCore.h>

    @interface Shape_05ViewController : UIViewController {

        CALayer                     *rootLayer;

        CAShapeLayer            *shapeLayer;

        CGMutablePathRef        pentagonPath;
        CGMutablePathRef        starPath;

        int animationCount;
        CABasicAnimation *animation;
        NSTimer *repeatingTimer;

    }

@property (assign, readwrite) NSTimer *repeatingTimer;

    -(void) startAnimation: (NSTimer*)theTimer;
    -(void) viewDidLoad;
    -(void) startSequence;

    @end

    #import "Shape_05ViewController.h"

    @implementation Shape_05ViewController

    @synthesize repeatingTimer;


    - (void)loadView 
    {

        UIView *appView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        appView.backgroundColor = [UIColor blackColor];
        self.view = appView;
        [appView release];
        rootLayer   = [CALayer layer];
        rootLayer.frame = self.view.bounds;
        [self.view.layer addSublayer:rootLayer];


        //Pentagon Path

        pentagonPath = CGPathCreateMutable();
        CGPoint center = self.view.center;
        CGPathMoveToPoint(pentagonPath, nil, center.x, center.y - 75.0);

        for(int i = 1; i < 5; ++i) {
            CGFloat x = - 75.0 * sinf(i * 2.0 * M_PI / 5.0);
            CGFloat y =  - 75.0 * cosf(i * 2.0 * M_PI / 5.0);
            CGPathAddLineToPoint(pentagonPath, nil,center.x + x, center.y + y);
        }
        CGPathCloseSubpath(pentagonPath); //This seems to be fixed in 4.0

        //Star Path

        starPath = CGPathCreateMutable();
        center = self.view.center;
        CGPathMoveToPoint(starPath, NULL, center.x, center.y + 75.0);
        for(int i = 1; i < 5; ++i) {
            CGFloat x =  75.0 * sinf(i * 4.0 * M_PI / 5.0);
            CGFloat y =  75.0 * cosf(i * 4.0 * M_PI / 5.0);
            CGPathAddLineToPoint(starPath, NULL, center.x + x, center.y + y);
        };
        CGPathCloseSubpath(starPath);


        //Create Shape

        shapeLayer = [CAShapeLayer layer];
        shapeLayer.path = pentagonPath;
        UIColor *fillColor = [UIColor colorWithWhite:0.9 alpha:1.0];
        shapeLayer.fillColor = fillColor.CGColor; 
        shapeLayer.fillRule = kCAFillRuleNonZero;
        [rootLayer addSublayer:shapeLayer];

    }


    -(void) viewDidLoad {

        NSLog(@"viewDidLoad");
        animationCount = 0;

        [NSThread detachNewThreadSelector:@selector(startSequence) toTarget:self withObject:nil];

    }

    -(void) startSequence {
        NSLog(@"startSequence");
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                          target:self
                                                        selector:@selector(startAnimation:)
                                                        userInfo:nil 
                                                         repeats:YES];
        [[NSRunLoop currentRunLoop] run];
        self.repeatingTimer = timer;
        [pool release];

    }

-(void)startAnimation: (NSTimer*)theTimer {

        NSLog(@"startAnimation");

        animation = [CABasicAnimation animationWithKeyPath:@"path"];
        animation.duration = 0.25;
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        animation.repeatCount = 0;
        animation.autoreverses = NO;
        animation.fillMode = kCAFillModeForwards;
        animation.removedOnCompletion = NO;

        if( (animationCount % 2) == 0) {
            animation.fromValue = (id)pentagonPath;
            animation.toValue = (id)starPath;
        } else {
            animation.fromValue = (id)starPath;
            animation.toValue = (id)pentagonPath;
        };
        [shapeLayer addAnimation:animation forKey:@"animatePath"];
        animationCount++;

    }


    - (void)didReceiveMemoryWarning 
    {
        [super didReceiveMemoryWarning];
    }


    - (void)dealloc
    {
        CGPathRelease(starPath);
        CGPathRelease(pentagonPath);
        [super dealloc];
    }

    @end

OK after another Google trawl:
http://forums.macrumors.com/showthread.php?t=749518&highlight=cabasicanimation

I found out about this thing called NSTimer! Another search of this site revealed some good info:
How do I use NSTimer?

And about running NSTimer in its own thread:
Keep an NSThread containing an NSTimer around indefinitely? (iPhone)

So now I can offer this updated code example, which I hope may be useful to someone one day. By the way, I didn't try it yet, but apparently the following can be used to stop the timer:

[myTimer invalidate];
myTimer = nil;

Thanks to all here at this site, not only the most beautifully designed corner of the web but also a total lifesaver!

    #import <UIKit/UIKit.h>
    #import <QuartzCore/QuartzCore.h>

    @interface Shape_05ViewController : UIViewController {

        CALayer                     *rootLayer;

        CAShapeLayer            *shapeLayer;

        CGMutablePathRef        pentagonPath;
        CGMutablePathRef        starPath;

        int animationCount;
        CABasicAnimation *animation;
        NSTimer *repeatingTimer;

    }

@property (assign, readwrite) NSTimer *repeatingTimer;

    -(void) startAnimation: (NSTimer*)theTimer;
    -(void) viewDidLoad;
    -(void) startSequence;

    @end

    #import "Shape_05ViewController.h"

    @implementation Shape_05ViewController

    @synthesize repeatingTimer;


    - (void)loadView 
    {

        UIView *appView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        appView.backgroundColor = [UIColor blackColor];
        self.view = appView;
        [appView release];
        rootLayer   = [CALayer layer];
        rootLayer.frame = self.view.bounds;
        [self.view.layer addSublayer:rootLayer];


        //Pentagon Path

        pentagonPath = CGPathCreateMutable();
        CGPoint center = self.view.center;
        CGPathMoveToPoint(pentagonPath, nil, center.x, center.y - 75.0);

        for(int i = 1; i < 5; ++i) {
            CGFloat x = - 75.0 * sinf(i * 2.0 * M_PI / 5.0);
            CGFloat y =  - 75.0 * cosf(i * 2.0 * M_PI / 5.0);
            CGPathAddLineToPoint(pentagonPath, nil,center.x + x, center.y + y);
        }
        CGPathCloseSubpath(pentagonPath); //This seems to be fixed in 4.0

        //Star Path

        starPath = CGPathCreateMutable();
        center = self.view.center;
        CGPathMoveToPoint(starPath, NULL, center.x, center.y + 75.0);
        for(int i = 1; i < 5; ++i) {
            CGFloat x =  75.0 * sinf(i * 4.0 * M_PI / 5.0);
            CGFloat y =  75.0 * cosf(i * 4.0 * M_PI / 5.0);
            CGPathAddLineToPoint(starPath, NULL, center.x + x, center.y + y);
        };
        CGPathCloseSubpath(starPath);


        //Create Shape

        shapeLayer = [CAShapeLayer layer];
        shapeLayer.path = pentagonPath;
        UIColor *fillColor = [UIColor colorWithWhite:0.9 alpha:1.0];
        shapeLayer.fillColor = fillColor.CGColor; 
        shapeLayer.fillRule = kCAFillRuleNonZero;
        [rootLayer addSublayer:shapeLayer];

    }


    -(void) viewDidLoad {

        NSLog(@"viewDidLoad");
        animationCount = 0;

        [NSThread detachNewThreadSelector:@selector(startSequence) toTarget:self withObject:nil];

    }

    -(void) startSequence {
        NSLog(@"startSequence");
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                          target:self
                                                        selector:@selector(startAnimation:)
                                                        userInfo:nil 
                                                         repeats:YES];
        [[NSRunLoop currentRunLoop] run];
        self.repeatingTimer = timer;
        [pool release];

    }

-(void)startAnimation: (NSTimer*)theTimer {

        NSLog(@"startAnimation");

        animation = [CABasicAnimation animationWithKeyPath:@"path"];
        animation.duration = 0.25;
        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
        animation.repeatCount = 0;
        animation.autoreverses = NO;
        animation.fillMode = kCAFillModeForwards;
        animation.removedOnCompletion = NO;

        if( (animationCount % 2) == 0) {
            animation.fromValue = (id)pentagonPath;
            animation.toValue = (id)starPath;
        } else {
            animation.fromValue = (id)starPath;
            animation.toValue = (id)pentagonPath;
        };
        [shapeLayer addAnimation:animation forKey:@"animatePath"];
        animationCount++;

    }


    - (void)didReceiveMemoryWarning 
    {
        [super didReceiveMemoryWarning];
    }


    - (void)dealloc
    {
        CGPathRelease(starPath);
        CGPathRelease(pentagonPath);
        [super dealloc];
    }

    @end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文