5

Apple ドキュメントのサンプル プロジェクト「ZoomingPDFViewer」から直接取得した拡張 UIScrollView があります。

このプロジェクトを取得すると、UIScrollView 拡張クラス「PDFScrollView」を実行すると (sim およびデバイスで) 明らかなバグがあることに気付くでしょう。

ズームを十分にピンチすると、最終的には StoryBoard によって設定されたズーム スケールの制限に達しますが、もう一度ピンチして、制限を超えて進むことができます。

このクラスを自分のプロジェクトに実装しようとしましたが、このバグが発生しました。

何らかの理由で、ズームが終了した後、UIScrollView の zoomScale プロパティが任意に 1.0 に戻されるため、効果的にズームを無限大にピンチすることができます... zoomScale のリセットはコンテンツに影響を与えないことに注意してください...デモの PDF が画面上の 1 ピクセルになるまでズームアウトし続けることができます。

これまでに見たことがなく、カスタム UIScrollViews を大量に作成したことがあります。

それを解決するためにいくつかの手順を試しましたが、何も機能していないようです。UIScrollView がその zoomScale をそのようにリセットする原因を知っている人はいますか?

ズーム中にサブビューが削除および追加されているためではないかと思いましたが、スクロールビューにダミービューを配置してアンカーとして機能させましたが、それも機能しませんでした。

私が言ったように.. ZoomingPDFViewer は、iOS 6.0 を使用して、私が作業している正確なコードです

どんなアイデアでも大歓迎です。以下のサンプルコード

- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
NSLog(@"Ending Zoom %0.2f %0.2f", [self zoomScale], scale);

// Set the new scale factor for the TiledPDFView.
_PDFScale *= scale;

// Calculate the new frame for the new TiledPDFView.
CGRect pageRect = CGPDFPageGetBoxRect(_PDFPage, kCGPDFMediaBox);
pageRect.size = CGSizeMake(pageRect.size.width*_PDFScale, pageRect.size.height*_PDFScale);


// Create a new TiledPDFView based on new frame and scaling.
TiledPDFView *tiledPDFView = [[TiledPDFView alloc] initWithFrame:pageRect scale:_PDFScale];
[tiledPDFView setPage:_PDFPage];

// Add the new TiledPDFView to the PDFScrollView.
[self addSubview:tiledPDFView];
self.tiledPDFView = tiledPDFView;

NSLog(@"End of end zoom %0.2f", [self zoomScale]);

}

これはエンド スクロール デリゲートです...この両方のログは、まさに期待どおりの zoomScale を生成します...つまり、実際にズームしたと仮定して、1.0 以外の任意の数値です。

次に、layoutSubviews が呼び出されます。

// Use layoutSubviews to center the PDF page in the view.
- (void)layoutSubviews 
{
[super layoutSubviews];

// Center the image as it becomes smaller than the size of the screen.

CGSize boundsSize = self.bounds.size;
CGRect frameToCenter = self.tiledPDFView.frame;

// a bunch of code that sets frameToCenter

self.tiledPDFView.frame = frameToCenter;
self.backgroundImageView.frame = frameToCenter;

/*
 To handle the interaction between CATiledLayer and high resolution screens, set the tiling view's contentScaleFactor to 1.0.
 If this step were omitted, the content scale factor would be 2.0 on high resolution screens, which would cause the CATiledLayer to ask for tiles of the wrong scale.
 */
self.tiledPDFView.contentScaleFactor = 1.0;

NSLog(@"Subviews Layed Out %0.2f", [self zoomScale]);
}

この時点で、zoomScale は何があっても 1.0 を報告します...これは、End Zoom デリゲート メソッドが適切なズーム スケールを報告した後 0.003 秒をトレースします。

4

2 に答える 2

4

ええ、これは iOS 3 の頃に発生しました。グローバルな測定値ではなく、zoomScale常にscrollViewの現在の状態に関連しています。ズームするたびに、現在の全体的なズーム スケールを基準にして、最小ズーム スケールと最大ズーム スケールを再計算する必要があります。

これは私が過去に使用したコードです。それはあなたにプロセスの要点を与えるはずです:

早い段階で、必要な値を取得します。

- (void) viewDidLoad
{
    [super viewDidLoad];
    ...
    // Squirrel away min and max zoom values from nib
    sMinZoomScale = self.scrollView.minimumZoomScale; // the very minimum
    sMaxZoomScale = self.scrollView.maximumZoomScale; // the very maximum
    sGlobalZoomScale = 1.0f;  // we're currently at 100% size
    ...
}

そして残り(self.navigationViewscrollViewのコンテンツビューです):

- (void) scrollViewDidEndZooming:(UIScrollView *)scrollView
                        withView:(UIView *)view
                         atScale:(CGFloat)scale
{
    // after a zoom, change the resolution of our map
    sGlobalZoomScale *= scale;
    // Peg the scale to minZoom and maxZoom, in case of rounding errors
    sGlobalZoomScale = MIN(MAX(sMinZoomScale, sGlobalZoomScale), sMaxZoomScale);
    self.navigationView.globalZoomScale = sGlobalZoomScale;
    self.navigationView.globalScaleTransform = self.globalScaleTransform;
    [self updateResolution];

    // throw out all tiles so they'll reload at the new resolution
    [self.navigationView setNeedsDisplay];
}

// By the time we get here, the scrollview's applied a fake scale and translate transform, and
//   altered the scrollview's zoom scale. BUT, the navigationview is as it ever was.
- (void) updateResolution
{
    CGFloat zoomScale = [self.scrollView zoomScale];

    CGSize oldContentViewSize = self.navigationView.frame.size;    
    // zooming properly resets contentsize as it happens.
    CGSize newContentSize = self.scrollView.contentSize;

    CGPoint newContentOffset = self.scrollView.contentOffset;
    CGFloat xMult = newContentSize.width / oldContentViewSize.width;
    CGFloat yMult = newContentSize.height / oldContentViewSize.height;

    newContentOffset.x *= xMult;
    newContentOffset.y *= yMult;

    CGFloat currentMinZoom = self.scrollView.minimumZoomScale;
    CGFloat currentMaxZoom = self.scrollView.maximumZoomScale;

    CGFloat newMinZoom = currentMinZoom / zoomScale;
    CGFloat newMaxZoom = currentMaxZoom / zoomScale;

        // Reset zoom scales temporarily so we can patch up the revised content view
    // don't call our own set..zoomScale, 'cause they eventually call this method.  Infinite recursion is uncool.  
    [self.scrollView setMinimumZoomScale:1.0f];
    [self.scrollView setMaximumZoomScale:1.0f];
    [self.scrollView setZoomScale:1.0f animated:NO];

    [self.navigationView setFrame:CGRectMake(0.0f, 0.0f, newContentSize.width, newContentSize.height)];
    [self.scrollView setContentSize:newContentSize];
    [self.scrollView setContentOffset:newContentOffset animated:NO];

    [self.scrollView setMinimumZoomScale:newMinZoom];
    [self.scrollView setMaximumZoomScale:newMaxZoom];
}

お役に立てれば。

于 2012-09-28T16:03:37.270 に答える
2

ここでの問題は、Apple のサンプル コードでは、- (UIView *)viewForZoomingInScrollView:常に再インスタンス化されているスケーリング対象のビューを返していることです。すぐに、戻り値は別のオブジェクトになり、UIScrollView はこれをズーム スケールのリセットとして解釈し、無限にスクロールできるようにします。

Apple のサンプル コードを適切に修正する方法は (まだ) わかりませんが、有効な解決策には、リセットされないダミー ビューに UIScrollView を固定し、それ以外のすべてを手動でスケーリングすることが含まれます。

于 2012-10-01T16:04:20.197 に答える