发生 uiscrollview 事件时未触发 NSTimer
Posted
技术标签:
【中文标题】发生 uiscrollview 事件时未触发 NSTimer【英文标题】:NSTimer not fired when uiscrollview event occurs 【发布时间】:2012-02-01 04:08:40 【问题描述】:我有一个 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"];
【问题讨论】:
UIScrollView pauses NSTimer while scrolling的可能重复 【参考方案1】: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 在底部,您将看到可以选择的模式的定义。还有,传说有它,你可以编写自己的自定义模式,但恐怕很少有人能活着讲述这个故事。
【讨论】:
嘿@GregPrice。感谢您的解释,即使是 3 年后。但是,文档说scheduledTimerWithTimeInterval:...
创建了一个计时器并以默认模式将其安排在当前运行循环中。那么为什么在默认的 RunLoop 中添加两次,而不是在NSRunLoopCommonModes
模式下添加一次呢?
UIScrollView
在UITrackingRunLoopMode
中运行运行循环,这与NSDefaultRunLoopMode
不同。如果您还希望它在其他模式下运行,仅将计时器安排为默认模式是不够的。
对于 Swift 3:RunLoop.current.add(self.myTimer, forMode: .commonModes)
【参考方案2】:
还有一件事(c)
-
使用 timerWithTimeInterval 方法来避免在 DefaultMode 中向 runloop 添加定时器
使用 mainRunLoop
所以:
self.myTimer = [NSTimer timerWithTimeInterval:280 target:self 选择器:@selector(doStuff) userInfo:nil repeats:NO]; [[NSRunLoop mainRunLoop] addTimer:self.myTimer forMode:NSRunLoopCommonModes];
【讨论】:
以上是关于发生 uiscrollview 事件时未触发 NSTimer的主要内容,如果未能解决你的问题,请参考以下文章