17

我有一个 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"];
}
4

2 回答 2

61

iOS 应用程序在 NSRunLoop 上运行。每个 NSRunLoop 对不同的任务都有不同的执行模式。例如,默认的 nstimer 计划在 NSRunLoop 上的 NSDefaultRunMode 下运行。然而,这意味着某些 UIEvents,scrollviewing 是一个,将中断计时器,并将其放在队列中,以便在事件停止更新时立即运行。在您的情况下,为了让计时器不被中断,您需要将其安排为不同的模式,即 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 在底部,您将看到可以选择的模式的定义。此外,传说有它,您可以编写自己的自定义模式,但恐怕很少有人能活着讲述这个故事。

于 2012-02-01T06:04:06.160 回答
1

还有一件事(c)

  1. 使用 timerWithTimeInterval 方法以避免在 DefaultMode 中将计时器添加到 runloop
  2. 使用 mainRunLoop

所以:

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

于 2019-07-08T12:41:16.427 回答