我有一个UIImageView的动画集代表当前值并且不断向上滴答...理想情况下永远不会停止,在视图中也是一个scrollView或者当我滚动或放大scrollView时,动画停止,并且当scrollView完全停止移动时再次启动。我认为这是由于线程问题,因为重绘元素都发生在主线程上,起初我尝试了UIView动画,然后甚至核心动画都没有效果......有没有办法让我的蛋糕也吃掉它?
任何和所有的帮助将不胜感激
代码如下
- (void)TestJackpotAtRate:(double)rateOfchange
{
double roc = rateOfchange;
for (int i = 0; i < [_jackPotDigits count]; ++i)
{
roc = rateOfchange/(pow(10, i));
UIImageView *jackpotDigit = [_jackPotDigits objectAtIndex:i];
float foreveryNseconds = 1/roc;
NSDictionary *dict = @{@"interval" : [NSNumber numberWithFloat:foreveryNseconds],
@"jackPotDigit" : jackpotDigit
};
[NSTimer scheduledTimerWithTimeInterval:foreveryNseconds target:self selector:@selector(AscendDigit:) userInfo:dict repeats:YES];
}
}
-(void)AscendDigit:(NSTimer*)timer
{
NSDictionary *dict = [timer userInfo];
NSTimeInterval interval = [(NSNumber*)[dict objectForKey:@"interval"] floatValue];
UIImageView *jackpotDigit = [dict objectForKey:@"jackPotDigit"];
float duration = (interval < 1) ? interval : 1;
if (jackpotDigit.frame.origin.y < -230 )
{
NSLog(@"hit");
[timer invalidate];
CGRect frame = jackpotDigit.frame;
frame.origin.y = 0;
[jackpotDigit setFrame:frame];
[NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(AscendDigit:) userInfo:dict repeats:YES];
}
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^
{
CGRect frame = [jackpotDigit frame];
double yDisplacement = 25;
frame.origin.y -= yDisplacement;
[jackpotDigit setFrame:frame];
}
completion:^(BOOL finished)
{
}];
}
正如danypata在我的评论中通过这个帖子指出My custom UI elements are not being updated while UIScrollView is scrolled它与NStimer线程而不是动画线程有关,或者如果有人可以澄清的话。在任何情况下,当滚动它似乎所有滚动事件得到独占使用主循环,解决方案是将您用于动画的计时器放入相同的循环模式,即UITrackingLoopMode,所以它也可以使用主循环滚动和......
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:foreveryNseconds target:self selector:@selector(AscendDigit:) userInfo:dict repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
然后。
在使用scrollView delegate
方法的UIScrollview滚动期间,还有另一种控制动画的方法;使用Timer启动动画,而不是使用scrollViewWillBeginDragging
方法停止计时器,并继续使用displayLink
等动画,例如:
// Declare an displayLink
var displayLink: CADisplayLink?
// delegate your scrollview
self.scrollView.delegate = self
// start your anmiations
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.startTimer()
}
// animation block
@objc private func shakeStartButton() {...}
// your animation timer
private func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(self.shakeStartButton), userInfo: nil, repeats: true)
timer?.fire()
}
private func startDisplayLinkIfNeeded() {
if displayLink == nil {
self.displayLink = CADisplayLink(target: self, selector: #selector(self.shakeStartButton))
displayLink?.add(to: .main, forMode: .tracking)
// Render frame only one time in second
displayLink?.preferredFramesPerSecond = 1
}
}
private func stopDisplayLink() {
displayLink?.invalidate()
displayLink = nil
}
extension YourViewController: UIScrollViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
self.timer?.invalidate()
self.startDisplayLinkIfNeeded()
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if !decelerate {
self.stopDisplayLink()
self.startTimer()
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
self.stopDisplayLink()
self.startTimer()
}
}
注意:这比@gehan的答案稍微长一点,但它也可能有助于其他事情吗?