1

設定:

クラスの助けを借りて水平ページングUIScrollViewを設定しましたLXPagingViews(「のぞき」を簡単に追加するためUIScrollView)。これが設定されているので、 で異なるビュー間をフリックできますUIScrollView。すべてのビューに を追加したUIPinchGestureRecognizerので、ユーザーがビューをピンチすると、「ズーム」アニメーションが表示され、詳細ビューに移動します。より明確にするためのスクリーンショット:

マイページング UIScrollView

問題:

ビューの 1 つをつまむと、ズーム アニメーションが開始され、ビューが詳細ビューに切り替わります。の最後のビューを除いて、これは正常に機能しUIScrollViewます。最後のビュー (2 つ以上ある限り、ビューの数は関係ありません) で、アニメーションを再生すると、タップしたビューの背後に新しいビューが生成され、そのビューがアニメーション化されます。これにより、奇妙なアニメーションが作成されます。また、新しいビューが生成されるため、ビューはアニメーションによって入力からブロックされません。これは、ユーザーがすばやくピンチすることで、複数のビューをすばやく生成できることを意味します。

このスクリーンショットが問題を少し説明していることを願っています:

ユーザーがピンチすると、新しいビューが背後に生成され、アニメーション化されます

私が試したこと:

  • ジェスチャ レコグナイザーのスーパービュー サブビューをデバッグして、さらにビューが生成されるかどうかを確認する
  • どのビューがアニメーション化されるかを監視します。ユーザーがピンチするたびに、何らかの理由で別のビューがアニメーション化されます
  • 遅延読み込みの代わりに画像を設定する別の方法を使用しようとしました。役に立たなかった
  • 他の画像、多かれ少なかれビュー、向きの違い、空のビューを試しました。

コード:

ジェスチャ レコグナイザーをビューに追加します。

- (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:

ここに小さなデモ プロジェクトをアップロードしました。それを使用する方法は、シミュレーター (またはデバイス) を横向きに設定し、Peeping Paging View に移動し、ビュー (最初のものを除く) をピンチ/タップしてみてください。ご覧のとおり、ビューはズームされますが、最後のビューを除いて、そのビューの背後に新しいビューが生成され、そのビューがズームされます (「9」は同じサイズのままです)。

コードは にありPeepingPagingViewController.mます。

解決策 (Oladya Kane に感謝):

右端に表示されているインデックスが、誤って左端に表示されているインデックスとしてインデックス付けされています。私が変更しなければならなかったコードは次の行でした:

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

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

1 に答える 1