15

NSScrollView (myScrollView) にラップされた NSView (myView) があります。ズームイン/ズームアウト ボタンを使用して、ユーザーは myView のスケールを変更できます。ユーザーが現在 myView の特定の場所にスクロールしている場合、ズームが行われた後、ビューのその部分を画面上に保持したいと思います。

次のようなコードがあります。

    // preserve current position in scrollview
    NSRect oldVisibleRect = [[myScrollView contentView] documentVisibleRect];
    NSPoint oldCenter = NSPointFromCGPoint(CGPointMake(oldVisibleRect.origin.x + (oldVisibleRect.size.width  / 2.0),
                                                       oldVisibleRect.origin.y + (oldVisibleRect.size.height / 2.0)));

    // adjust my zoom
    ++displayZoom;
    [self scaleUnitSquareToSize:NSSizeFromCGSize(CGSizeMake(0.5, 0.5))];
    [self calculateBounds];  // make sure my frame & bounds are at least as big as the visible content view
    [self display];

    // Adjust scroll view to keep the same position.
    NSRect newVisibleRect = [[myScrollView contentView] documentVisibleRect];
    NSPoint newOffset = NSPointFromCGPoint(CGPointMake((oldCenter.x * 0.5) - (newVisibleRect.size.width  / 2.0),
                                                       (oldCenter.y * 0.5) - (newVisibleRect.size.height / 2.0)));
    if (newOffset.x < 0)
        newOffset.x = 0;
    if (newOffset.y < 0)
        newOffset.y = 0;

    [[myScrollView contentView] scrollToPoint: newOffset];
    [myScrollView reflectScrolledClipView: [myScrollView contentView]];

かなり近いように思えますが、完全に正しくはなく、何が間違っているのかわかりません。私の2つの質問は次のとおりです。

1)次のような組み込みのものがありませんか:

   [myView adjustScaleBy: 0.5 whilePreservingLocationInScrollview:myScrollView];

2)そうでない場合、上記の「長い道のり」のアプローチで私が間違っていることを誰かが見ることができますか?

ありがとう!

4

3 に答える 3

12

スケーリング後に同じスクロール位置を維持するのは簡単ではありません。決定する必要があることの 1 つは、「同じ」とは何を意味するかということです。スケーリング前の可視領域の上部、中央、下部のどれをスケーリング後も所定の位置に維持したいですか?

または、より直感的に、開始時にドキュメントを下にスクロールするパーセンテージに等しい、表示されている四角形の下のパーセンテージにとどまる位置が必要ですか (たとえば、スクローラーの親指の中心が上に移動しないか、スケール中にダウンすると、親指が伸びたり縮んだりします)。

後者の効果が必要な場合は、NSScrollView の verticalScroller と horizo​​ntalScroller を取得し、それらの「floatValue」を読み取る方法があります。これらは 0 から 1 に正規化されます。「0」はドキュメントの先頭にいることを意味し、1 はドキュメントの最後にいることを意味します。スクローラーにこれを要求することの良い点は、ドキュメントが NSScrollView よりも短い場合でも、スクローラーは「floatValue」のすべてのケースで適切な回答を返すため、これを特別なケースにする必要がないことです。

サイズを変更したら、NSScrollView のスクロール位置をスケール前と同じパーセンテージに設定しますが、悲しいことに、ここで手を少し振ってみます。コードでしばらくこれを行っていませんが、覚えているように、NSScrollers の「floatValue」を直接設定することはできません。スクロールされているように見えますが、実際には NSScrollView には影響しません。

そのため、通過したいパーセンテージに基づいてドキュメントの新しい左上点を計算するために、いくつかの計算を記述する必要があります。たとえば、y 軸では、「ドキュメントがscrollView の contentView よりも短い場合は、ポイント 0 までスクロールします。それ以外の場合は、((contentView の高さ - documentView の高さ) * oldVerticalPercentage) のポイントまでスクロールします。" もちろんX軸も同様です。

また、ここで -display を呼び出す必要はなく、一般的にこれを呼び出すべきではないとほぼ確信しています。(-setNeedsDisplay: せいぜい。)

-ウィル

于 2009-09-20T03:17:38.997 に答える
7

これは古い質問ですが、これを探している人が私の答えが役立つことを願っています...

float zoomFactor = 1.3;

-(void)zoomIn
{
    NSRect visible = [scrollView documentVisibleRect];
    NSRect newrect = NSInsetRect(visible, NSWidth(visible)*(1 - 1/zoomFactor)/2.0, NSHeight(visible)*(1 - 1/zoomFactor)/2.0);
    NSRect frame = [scrollView.documentView frame];

    [scrollView.documentView scaleUnitSquareToSize:NSMakeSize(zoomFactor, zoomFactor)];
    [scrollView.documentView setFrame:NSMakeRect(0, 0, frame.size.width * zoomFactor, frame.size.height * zoomFactor)];

    [[scrollView documentView] scrollPoint:newrect.origin];
}

-(void)zoomOut
{
    NSRect visible = [scrollView documentVisibleRect];
    NSRect newrect = NSOffsetRect(visible, -NSWidth(visible)*(zoomFactor - 1)/2.0, -NSHeight(visible)*(zoomFactor - 1)/2.0);

    NSRect frame = [scrollView.documentView frame];

    [scrollView.documentView scaleUnitSquareToSize:NSMakeSize(1/zoomFactor, 1/zoomFactor)];
    [scrollView.documentView setFrame:NSMakeRect(0, 0, frame.size.width / zoomFactor, frame.size.height / zoomFactor)];

    [[scrollView documentView] scrollPoint:newrect.origin];
}
于 2011-06-16T05:40:58.257 に答える
7

私はあなたがタイピングが好きすぎると思います… ;-)

// instead of this:
NSPoint oldCenter = NSPointFromCGPoint(CGPointMake(oldVisibleRect.origin.x +
    (oldVisibleRect.size.width  / 2.0),

// use this:
NSPoint oldCenter = NSMakePoint(NSMidX(oldVisibleRect), NSMaxY(oldVisibleRect));

// likewise instead of this:
[self scaleUnitSquareToSize:NSSizeFromCGSize(CGSizeMake(0.5, 0.5))];

// use this:
[self scaleUnitSquareToSize:NSMakeSize(0.5, 0.5)];

// and instead of this
NSPoint newOffset = NSPointFromCGPoint(CGPointMake(
    (oldCenter.x * 0.5) - (newVisibleRect.size.width  / 2.0),
    (oldCenter.y * 0.5) - (newVisibleRect.size.height / 2.0)));

// use this:
NSPoint newOffset NSMakePoint(
    (oldCenter.x - NSWidth(newVisibleRect)) / 2.f,
    (oldCenter.y - NSHeight(newVisibleRect)) / 2.f);
于 2009-09-30T15:37:32.933 に答える