当 uiscrollview 事件发生时,NSTimer 不会被触发

发布于 2024-12-29 23:24:33 字数 1154 浏览 2 评论 0原文

我有一个 UIImageView 放置在 UIScrollView 中,基本上这个 UIImageView 保存非常大的地图,并在预定义路径上创建动画,并用“箭头”指向导航方向。

但是,每当 uiscrollevents 发生时,我认为 MainLoop 会冻结并且 NSTimer 不会被触发,并且动画也会停止。

UIScrollView、CAKeyFrameAnimation 或 NSTimer 上是否有任何现有属性可以解决此问题?

//viewDidLoad
   self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(drawLines:) userInfo:nil repeats:YES];

- (void)drawLines:(NSTimer *)timer {

   CALayer *arrow = [CALayer layer];
   arrow.bounds = CGRectMake(0, 0, 5, 5);
   arrow.position = CGPointMake(line.x1, line.y1);
   arrow.contents = (id)([UIImage imageNamed:@"arrow.png"].CGImage);

   [self.contentView.layer addSublayer:arrow];

   CAKeyframeAnimation* animation = [CAKeyframeAnimation animation];
   animation.path = path;
   animation.duration = 1.0;
   animation.rotationMode = kCAAnimationRotateAuto; // object auto rotates to follow the path
   animation.repeatCount = 1;
   animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
   animation.fillMode = kCAFillModeForwards;

   [arrow addAnimation:animation forKey:@"position"];
}

I have a UIImageView placed in UIScrollView, Basicly this UIImageView holds very big map, and created animation on a predefined path with "arrows" pointed navigation direction.

But, whenever uiscrollevents occurs, I think MainLoop freezes and NSTimer being not fired, and animation stopped.

Are there any existing property, which solves this problem, on UIScrollView, CAKeyFrameAnimation or NSTimer?

//viewDidLoad
   self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(drawLines:) userInfo:nil repeats:YES];

- (void)drawLines:(NSTimer *)timer {

   CALayer *arrow = [CALayer layer];
   arrow.bounds = CGRectMake(0, 0, 5, 5);
   arrow.position = CGPointMake(line.x1, line.y1);
   arrow.contents = (id)([UIImage imageNamed:@"arrow.png"].CGImage);

   [self.contentView.layer addSublayer:arrow];

   CAKeyframeAnimation* animation = [CAKeyframeAnimation animation];
   animation.path = path;
   animation.duration = 1.0;
   animation.rotationMode = kCAAnimationRotateAuto; // object auto rotates to follow the path
   animation.repeatCount = 1;
   animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
   animation.fillMode = kCAFillModeForwards;

   [arrow addAnimation:animation forKey:@"position"];
}

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

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

发布评论

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

评论(2

花海 2025-01-05 23:24:33

iOS 应用程序在 NSRunLoop 上运行。每个NSRunLoop对于不同的任务都有不同的执行模式。例如,默认的 nstimer 被安排在 NSRunLoop 上的 NSDefaultRunMode 下运行。然而,这意味着某些 UIEvent(滚动查看就是其中之一)将中断计时器,并将其放入队列中,以便在事件停止更新时立即运行。在您的情况下,为了使计时器不被中断,您需要将其安排为不同的模式,即 NSRunLoopCommonModes,如下所示:

  self.myTimer =  [NSTimer scheduledTimerWithTimeInterval:280
                                                                 target:self
                                                               selector:@selector(doStuff)
                                                               userInfo:nil
                                                                repeats:NO];
  [[NSRunLoop currentRunLoop] addTimer:self.myTimer forMode:NSRunLoopCommonModes]; 

此模式将允许您的计时器不被滚动中断。
您可以在此处找到有关此信息的更多信息:https://developer.apple.com/documentation/foundation/ nsrunloop
在底部,您将看到可供选择的模式的定义。另外,据传说,你可以编写自己的自定义模式,但恐怕很少有人能活着讲述这个故事。

iOS Applications run on an NSRunLoop. Each NSRunLoop has different modes of execution for different tasks. For example, the default nstimer is scheduled to run under the NSDefaultRunMode on the NSRunLoop. What this means however is that certain UIEvents, scrollviewing being one, will interrupt the timer, and place it on a queue to be run as soon as the event stops updating. In your case, in order to get the timer to not be interrupted, you need to schedule it for a different mode, namely NSRunLoopCommonModes, like so:

  self.myTimer =  [NSTimer scheduledTimerWithTimeInterval:280
                                                                 target:self
                                                               selector:@selector(doStuff)
                                                               userInfo:nil
                                                                repeats:NO];
  [[NSRunLoop currentRunLoop] addTimer:self.myTimer forMode:NSRunLoopCommonModes]; 

This mode will allow your timer to not be interrupted by scrolling.
You can find more about this info here: https://developer.apple.com/documentation/foundation/nsrunloop
At the bottom you will see the definitions of the modes you can choose from. Also, legend has it, you can write your own custom modes, but few have ever lived to tell the tale im afraid.

软的没边 2025-01-05 23:24:33

另一件事(c)

  1. 使用timerWithTimeInterval方法以避免在DefaultMode
  2. 使用mainRunLoop

中添加计时器到runloop所以:

self.myTimer = [NSTimertimerWithTimeInterval:280 target:selfselector:@selector(doStuff)userInfo:nilrepeats:NO];
[[NSRunLoop mainRunLoop] addTimer:self.myTimer forMode:NSRunLoopCommonModes];

One more thing (c)

  1. use timerWithTimeInterval method in order to avoid adding timer to runloop in DefaultMode
  2. use mainRunLoop

So:

self.myTimer = [NSTimer timerWithTimeInterval:280 target:self selector:@selector(doStuff) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:self.myTimer forMode:NSRunLoopCommonModes];

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