0

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

当用户在屏幕上滑动时:如果滑动大于某个阈值,则前面的imageView会以与滑动相同的方向离开屏幕,然后出现在后面的imageView后面。

所以我们计划将它用于图像队列。滑动成功后,前面的imageView会离开屏幕,然后居中在后面的ImageView(现在是前面)的后面,然后它会改变里面的图像。

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

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

滑动后的 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 的建议解决了这个问题!!

4

2 回答 2

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 以隐藏它,并在移动功能中删除 [微调器 removeFromSuperview]; 这条线。

addSubView 的问题是它改变了子视图的 zorder,它可能与此有关,但不确定..

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

于 2013-03-06T00:57:36.860 回答
0

原因可能是微调器的动画。当viewController包含一个tableView刷新频率很高时也会出现同样的现象。图层的重绘会破坏动画。如果spinner即将成为视图的子视图,就会发生这种现象。

于 2013-03-06T02:02:43.783 回答