2009-08-18 72 views
14

我有一個NSView(myView)包裝在NSScrollView(myScrollView)中。使用放大/縮小按鈕,用戶可以改變myView的比例。如果用戶當前正在滾動到myView中的特定位置,我想在縮放發生後將該部分視圖保留在屏幕上。如何在更改比例尺時在NSScrollView中保持滾動位置?

我有代碼看起來像這樣:

// 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]]; 

而且似乎有點接近,但它並不完全正確的,我想不出我做錯了什麼。我的兩個問題是:

1)是不是有一個內置的線沿線的東西:

[myView adjustScaleBy: 0.5 whilePreservingLocationInScrollview:myScrollView]; 

2)如果沒有,任何人都可以看到我在做什麼錯在我「很長的路要走周圍「的方法,以上?

謝謝!

回答

11

縮放後保持相同的滾動位置並不容易。你需要決定的一件事就是你的意思是「相同」 - 你想在縮放之前將可見區域的頂部,中部或底部保留在原位之後?

或者,更直觀地說,您是否希望在可見矩形中保留的位置的百分比等於您在開始時向下滾動文檔的百分比(例如,滾動條的中心不會「在縮放期間上下移動,拇指只是長大或縮小)。

如果你想要後一種效果,一種方法是獲取NSScrollView的verticalScroller和horizo​​ntalScroller,然後閱讀它們的'floatValue'。這些值從0到1進行了標準化,其中'0'表示您處於文檔的頂部,1表示您處於最後。關於詢問Scroller的好處是,如果文檔比NSScrollView短,那麼Scroller在所有情況下仍然會爲'floatValue'返回一個理智的答案,因此您不必特殊說明。

調整大小後,將NSScrollView的滾動位置設置爲與縮放前相同的百分比 - 但不幸的是,這裏是我揮動雙手的地方。在我的代碼中,我一段時間都沒有這樣做,但是我記得你不能直接設置NSScrollers的floatValue - 它們會看起來滾動,但它們實際上不會影響NSScrollView。

因此,您必須編寫一些數學運算來計算文檔中新的左上角點,這取決於您希望通過的百分比 - 例如,在y軸上,它看起來像, 「如果文檔現在比scrollView的contentView短,請滾動到0,否則滾動到((contentView的高度 - 文檔視圖的高度)* oldVerticalPercentage)下的文檔。」 X軸當然是相似的。

此外,我幾乎是積極的,你不需要打電話給這裏的顯示器,並且一般都不應該永遠稱之爲。 (-setNeedsDisplay:最多)

-Wil

+0

我想要的效果是:假設我正在看屏幕中間。當我放大(或-out)時,將它保留在屏幕中間。 謝謝! – Olie 2009-09-22 20:57:32

+0

優秀的答案!在將視圖滾動到計算出的原點後,我沒有在滾動條上設置floatValue,而是在我的滾動視圖上調用了reflectScrolledClipView:。這似乎讓滾動條處於正確的位置。不知道這是否正確,因爲這是我創建的第一個Mac應用程序,但它適用於我。 – afarnham 2013-08-13 15:16:45

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); 
+0

是的,我在發佈後不久就瞭解到這些。我來自iPhone世界,猜測NS名字對於我來說還是有點慢。謝謝! :) – Olie 2009-10-01 15:04:53

6

這是一個老問題,但我希望有人找這個發現我的答案有用...

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]; 
} 
+0

我發現它非常有用。這工作後,我嘗試了其他一些事情沒有。感謝您發佈它! – jbillfinger 2013-10-29 00:50:39

+1

這很好用!唯一的問題是調整窗口的大小(以及滾動視圖):內容再次滾動到左下角。 – 2013-11-21 20:42:25

+0

@NicolasMiari我也有麻煩,內容滾動到左下角,你有沒有找到一個解決方案? – 2016-11-16 06:22:31

相關問題