UIScrollView滚动事件阻止UIView动画

问题描述 投票:9回答:2

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

     }];

}
ios multithreading animation uiscrollview
2个回答
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];

然后。


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的答案稍微长一点,但它也可能有助于其他事情吗?

© www.soinside.com 2019 - 2024. All rights reserved.