9

I have an animating set of UIImageView's that represent a current value and continually keeps ticking upwards...ideally never stopping, also in the view is a scrollView or to and whenever I'm scrolling or zooming in the scrollView, the animation stops, and starts up again when the scrollView stops moving completely. I believe this is due to a threading issue since redrawing elements all happens on the main thread, At first i tried UIView animation and then even core animation to no effect...Is there a way to have my cake and eat it too?

Any and all help would be appreciated

code follows

- (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)
     {

     }];

}
4

2 回答 2

30

正如 danypata在我通过此线程的评论中指出的那样,当 UIScrollView 滚动时,我的自定义 UI 元素没有被更新它与 NStimer 线程而不是动画线程有关,或者如果有人可以澄清的话,可能两者兼而有之。在任何情况下,当滚动时,似乎所有滚动事件都独占使用主循环,解决方案是将用于制作动画的计时器置于UITrackingLoopMode相同的循环模式中,因此它也可以使用主循环滚动和...

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:foreveryNseconds target:self selector:@selector(AscendDigit:) userInfo:dict repeats:YES];

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

多田。

于 2013-05-15T08:25:31.887 回答
0

在 UIScrollview 滚动期间,还有另一种方法可以使用scrollView delegate方法控制动画;使用 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 答案长一点,但它也可能对其他事情有所帮助?

于 2019-03-14T11:17:00.510 回答