添加微调器时,UIView动画失败了吗?

时间:2013-03-06 00:36:50

标签: iphone ios objective-c uianimation

我目前正在构建一个UI插件。这个插件有2个imageViews,一个在另一个之上。

当用户在屏幕上滑动时:如果滑动大于阈值,则前面的imageView将使屏幕与滑动方向相同,然后显示在后面的imageView后面。

因此我们计划将其用于图像队列。成功滑动后,前面的imageView将离开屏幕,然后居中于backImageView(现在是前面)后面,然后它会更改内部的图像。

当没有更多图像时,我设置了一个微调器,表示我们正在从服务器下载更多图像。

我们遇到了一个我们无法解释的错误 - 当我们将微调器添加到视图中时,我们的动画出现故障

刷过的imageView不再离开屏幕,而是返回原始位置。

我们对此非常困惑,并确认

                 [self.view addSubview:spinner];

将导致我们的动画出现意外行为。

附上请移动方法:

- (void)move:(UIPanGestureRecognizer *)sender {
    CGPoint translatedPoint = [sender translationInView:self.frontView];

    if([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
        _firstX = self.frontView.center.x;
        _firstY = self.frontView.center.y;
    }

    translatedPoint = CGPointMake(_firstX+translatedPoint.x, _firstY+translatedPoint.y);
    [self.frontView setCenter:translatedPoint];

    if ([(UIPanGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
        // Calculate the if the x-movement is greater than a threshold
        float xTravelled = 0;
        if (self.frontView.center.x > _firstX)
            xTravelled = self.frontView.center.x - _firstX;
        else
            xTravelled = _firstX - self.frontView.center.x;

        // Only move if xTravelled is greater than threshold
        if (xTravelled > self.frontView.window.frame.size.width / 3) {
            NSLog(@"Swipe detected, currentIndex:%d", currentIndex);

            // Lock view from panning until animation is finished.
            self.view.userInteractionEnabled = NO;

            float newXPosition;
            if (self.frontView.center.x > _firstX) {
                newXPosition = (float) self.view.frame.size.width * 2;
            } else {
                newXPosition = (float) -2 * self.view.frame.size.width;
            }

            // We should trigger a fetch as soon as the back image is empty.
            if (![self getBackView].image) {
                double delayInSeconds = 2.0;
                dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
                dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                    //[self fetchComplete];
                    [spinner stopAnimating];
                    [spinner removeFromSuperview];
                    self.view.userInteractionEnabled = YES;
                });

                // Pop up spinner if necessary
                if (![spinner isAnimating]) {
                    self.view.userInteractionEnabled = NO;
                    [spinner setCenter:CGPointMake(_firstX, _firstY)];
                    [spinner startAnimating];
                    /* THIS BREAKS OUR ANIMATION - Enable it to see 
                     [self.view addSubview:spinner];
                     */
                }
            }

            // Animate the rest of the swipe
            [UIView \
             animateWithDuration:0.5f delay:0.0f options:UIViewAnimationOptionTransitionNone
             animations:^{
                 // Use smooth animation to move the top image out of the way
                 [self.frontView setCenter:CGPointMake(newXPosition, self.frontView.center.y)];
             }
             completion:^(BOOL finished){
                 // Set it to be physically behind the back image
                 [self.view sendSubviewToBack:self.frontView];
                 //[self.frontView setCenter:CGPointMake(_firstX, _firstY)];  // why not necessary??

                 // Now change the picture
                 UIImage *next = [self nextImage];
                 self.frontView.image = next;

                 // update self.top to reference the new back image
                 self.frontView = [self getBackView];

                 // Do not override spinner's block 
                 if (![spinner isAnimating])
                     self.view.userInteractionEnabled = YES;
             }];
        } else {
            NSLog(@"Swipe NOT detected");
            [UIView \
             animateWithDuration:0.5f delay:0.0f options:UIViewAnimationOptionAllowUserInteraction
             animations:^{
                 [self.frontView setCenter:CGPointMake(_firstX, _firstY)];
             } completion:^(BOOL finished) {
                 self.view.userInteractionEnabled = YES;
             }];
        }
    }

我知道这是相当长的,但我已将此错误隔离到一个示例项目中,您可以在计算机上下载并运行该项目。此示例项目位于:http://bit.ly/WO4cEI

我们怀疑向self.view添加子视图会导致[self.view sendSubviewToBack:self.frontView]失败。但我们不确定为什么这会导致我们的动画失败。

感谢您的帮助!!

修改

@ user2113425的建议解决了这个问题!!

2 个答案:

答案 0 :(得分:1)

首先,您无需在此时添加微调器。

- (void)viewDidLoad
{
    [super viewDidLoad];
    UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(move:)];
    [panRecognizer setMinimumNumberOfTouches:1];
    [panRecognizer setMaximumNumberOfTouches:1];

    [panRecognizer setDelegate:self];
    [self.view addGestureRecognizer:panRecognizer];
    self.view.userInteractionEnabled = YES;

    // Index starts at zero so we pick even.
    self.frontView = self.evenImage;

    // Setting the images
    images = [[NSArray alloc] initWithObjects:@"a.jpeg", @"b.jpeg", nil]; // @"c.jpeg", @"d.jpeg", @"e.jpeg", nil];

    currentIndex = 0;
    self.evenImage.image = [self nextImage];
    self.oddImage.image = [self nextImage];

    // Spinner
    spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    **spinner.hidesWhenStopped = YES;
    [self.view addSubview:spinner];**
}

你可以在viewDidLoad中添加微调器并设置hidesWhenStopped来隐藏它,并在移动函数中删除[spinner removeFromSuperview];这一行。

addSubView的问题在于它改变了子视图的zorder,它可能涉及但不确定..

有很多方法可以解决这个问题。

答案 1 :(得分:0)

原因可能是微调器的动画。当viewController包含一个刷新高频的tableView时会出现同样的现象。图层的重绘会打破动画。根据视图的子视图来调整微调器,使这种现象发生。