UIScrollView滚动事件阻止UIView动画

时间:2013-05-15 05:56:07

标签: ios multithreading animation uiscrollview

我有一组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)
     {

     }];

}

2 个答案:

答案 0 :(得分:29)

正如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];

多田。

答案 1 :(得分:0)

还有另一种方法可以使用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回答的时间要长一点,但也可能对其他事情有所帮助?