1

設置:怪異的行爲的UIView動畫

我有一個水平分頁UIScrollView建立與LXPagingViews類的幫助(方便地添加一個「偷窺」 UIScrollView)。這是設置的,所以你可以在UIScrollView的不同視圖之間滑動。我爲每個視圖添加了UIPinchGestureRecognizer,因此當用戶捏在視圖上時,它會顯示「縮放」動畫,然後進入詳細視圖。一種用於更清晰的屏幕截圖:

My paging UIScrollView

問題:

當我捏的意見,變焦動畫開始一個和所述視圖繼續入詳細視圖。這工作正常,除了在UIScrollView的最後一個視圖。在最後一個視圖(無論它有多少個視圖,只要它有2個以上視圖無關),當動畫播放時,它會在我拍攝的視圖背後產生一個新視圖,併爲其創建動畫。這使得一個奇怪的動畫。此外,該視圖不會被動畫輸入阻止,因爲它產生了一個新的視圖。這意味着用戶可以通過快速捏造來快速生成多個視圖。

我希望這張截圖說明了這個問題有點:

When the user pinches, a new view spawns behind and animates

我曾嘗試:

  • 調試手勢識別的上海華子視圖,檢查是否有更多的意見產卵
  • 監視哪些視圖獲得了動畫效果。對於用戶的每一次捏,另一個視圖由於某種原因得到動畫
  • 試圖使用另一種方式設置圖像,而不是延遲加載。沒有幫助
  • 嘗試了其他圖像,越來越少的意見,方向差異和空視圖。

代碼:

添加手勢識別的觀點:

- (UIView<ReusableView> *)pagingView:(PagingView *)thePagingView reusableViewForPageIndex:(NSUInteger)thePageIndex withFrame:(CGRect)theFrame { 
    // View's Identifier 
    static NSString *theIdentifier = @"voucherDetailView"; 
    VoucherDetailView *thePageView = (VoucherDetailView *)[thePagingView dequeueReusableViewWithIdentifier:theIdentifier]; 
    if (thePageView == nil) { 
     thePageView = [[VoucherDetailView alloc] initWithFrame:theFrame]; 
    } else { 
     thePageView.frame = theFrame; 
    } 

    Voucher *voucher = [_vouchers objectAtIndex:thePageIndex]; 
    NSURL *fullVoucherImageUrl = [NSURL URLWithString:voucher.fullVoucherImage]; 
    [thePageView.voucher setImageWithURL:fullVoucherImageUrl placeholderImage:[UIImage imageNamed:@"11283253-nederland_kaart"]]; 

    // Gesture recognizer  
    UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(openZoomablePinch:)]; 
    [thePageView addGestureRecognizer:pinchGesture]; 

    return thePageView; 
} 

捏處理程序:

- (void)openZoomablePinch:(UIPinchGestureRecognizer*)sender { 
    // Only allow one pinch to activate the animation 
    if (sender.state == UIGestureRecognizerStateBegan) { 
     // Bring the view to the front so it doesn't clip with the peeping views 
     [sender.view.superview bringSubviewToFront:sender.view]; 
     CGAffineTransform trans = sender.view.transform; 
     [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveEaseOut 
         animations:^{ 
          sender.view.transform = CGAffineTransformScale(sender.view.transform, 1.15, 1.15); 
         } 
         completion:^(BOOL finished) { 
          if (finished && self.view.window) { 
           sender.view.transform = trans; 
           [self performSegueWithIdentifier:@"voucherZoomSegue" sender:self]; 
          } 
         }]; 
    } 
} 

編輯:PagingView代碼被調用的捏時的最後視圖:

UIView<ReusableView> *theRightMostReusableView = [self.visibleReusableViews lastObject]; 
    NSUInteger theRightMostPageIndex = (NSUInteger)floorf(CGRectGetMinX(theRightMostReusableView.frame)/thePageWidth); 
    while ((theRightMostPageIndex != MAX(0, self.numberOfItems - 1)) && (theRightMostPageIndex < theToIndex)) { 
     theRightMostPageIndex = MIN(theRightMostPageIndex + 1, MAX(0, self.numberOfItems - 1)); 
     CGFloat theMinX = theRightMostPageIndex * thePageWidth; 
     CGRect theRect = CGRectMake(theMinX, 0.0f, thePageWidth, thePageHeight); 
     UIView<ReusableView> *theReusableView = [self.dataSource pagingView:self reusableViewForPageIndex:theRightMostPageIndex withFrame:theRect]; 
     if (!CGRectContainsRect(theRect, theReusableView.frame)) { 
      @throw [NSException exceptionWithName:NSInternalInconsistencyException 
              reason:[NSString stringWithFormat: 
                @"theReusableView's frame (%@) must be contained by the given frame (%@)", 
                NSStringFromCGRect(theReusableView.frame), 
                NSStringFromCGRect(theRect)] 
             userInfo:nil]; 
     } 
     [self.visibleReusableViews addObject:theReusableView]; 
     [self addSubview:theReusableView]; 
    } 

編輯2:

我已上傳一個小演示項目here。使用它的方式是,將模擬器(或您的設備)設置爲橫向模式,轉到Peeping Paging View,然後嘗試捏取/點擊視圖(第一個視圖除外)。正如你所看到的那樣,除了最後一個視圖之外,這些視圖會被縮放,這樣會產生一個新的視圖,並放大一個視圖('9'保持相同的大小)。代碼PeepingPagingViewController.m

溶液(多虧Oladya凱恩):

最右邊的可見索引mistakingly索引爲最左邊的可見索引。我不得不改變代碼是行:

NSUInteger theRightMostPageIndex = (NSUInteger)floorf(CGRectGetMinX(theRightMostReusableView.frame)/thePageWidth); 

NSUInteger theRightMostPageIndex = MIN((NSInteger)floorf((CGRectGetMaxX(theRightMostReusableView.frame) - 0.1f)/thePageWidth), MAX(0, self.numberOfItems - 1)); 
+1

你是否在檢查最後一個視圖時檢查是否調用了'reusableViewForPageIndex'?如果是,您的ScrollView類的手勢出現問題。 – danypata

+0

好點!當我捏住最後一個視圖時,它確實會被調用,並且不會被其他視圖調用。你有什麼想法,我應該看看ScrollView類嗎?感謝您的幫助! – Thermometer

+0

檢查自定義視圖控制器中調用了'reusableViewForPageIndex'的哪個位置,並查看調用此方法的條件,某些情況是錯誤的,這就是爲什麼它創建另一個視圖。還要確保'dataSource'是正確的(沒有比它應該更多的視圖) – danypata

回答

1

我已經看了通過你演示代碼,發現以下錯誤:

當你捏手勢識別器被調用時,你爲它的發送者幀設置動畫。這迫使PageView佈局其子視圖 - >它調用你的委託方法

- (UIView<ReusableView> *)pagingView:(PagingView *)thePagingView reusableViewForPageIndex:(NSUInteger)thePageIndex withFrame:(CGRect)theFrame 

這裏你PagingView提供視圖,並將其添加視圖您上次查看之下,搞亂你的視圖層次。我想你可能會在某處使用某種標誌來阻止PagingView請求新的視圖。最奇怪的是,這種行爲只發生在最後一個視圖。 希望這會幫助你。

編輯:

我發現這個問題。 在該方法的最左邊和最右邊可見視圖

- (void)layoutSubviewsFromIndex:(NSUInteger)theFromIndex toIndex:(NSUInteger)theToIndex 

索引計算。但是,最右側的可視索引被錯誤計算爲最左邊的指標,因此,你需要替換這一行:

NSUInteger theRightMostPageIndex = (NSUInteger)floorf(CGRectGetMinX(theRightMostReusableView.frame)/thePageWidth); 

有了這一個:

NSUInteger theRightMostPageIndex = MIN((NSInteger)floorf((CGRectGetMaxX(theRightMostReusableView.frame) - 0.1f)/thePageWidth), MAX(0, self.numberOfItems - 1)); 

這將防止PagingView的請求已經新觀點可見的最後(最右邊)視圖。

+0

感謝您查看我的問題和演示項目。我會嘗試你的建議,防止調用'reusableViewForPageIndex'方法並在這裏報告。這真的很奇怪,這隻發生在最後一個視圖。 – Thermometer

+0

我修復了這個問題。通過向PagingView的委託添加布爾屬性「isLastView」。我已經在我的問題中發佈了代碼。仍然沒有解釋爲什麼它只發生在最後一個視圖(奇怪的行爲)。如果你能回答這個問題,我會獎勵賞金。 – Thermometer

+0

太棒了!非常感謝!我想我很容易看過那條線。我會獎勵賞金(在1小時內我可以這樣做)。 – Thermometer