2009-08-18 35 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

相关问题